Using DEVMODE Structure to change Orientation

I need to change the printer orientation to Landscape (with no user input) for a Win311 C Program.  I've allocated a Global handle for memory and used  a cast to (LPDEVMODE) to GlobalLock to a pointer (dmp), then used ExtDeviceMode () to get the driver's data - but when I ask for the data, with a structure variable - dmp->dmDeviceName - I get nada.  When I use a far pointer to a string with ExtDeviceMode (), and dump the string with MessageBox the data is there.  Anyone know an answer to this one?
zilleskAsked:
Who is Participating?
 
nietodCommented:
I'm answering for the moment.  But why not wait and test a bit more before you accept the answer.  Just to make sure.  I have the code you sent and will look over it as well.
0
 
nietodCommented:
Can you post your code?  It sounds almost like you are using GlobalLock wrong, but I'd like to see your code before making assumptions.
0
 
zilleskAuthor Commented:
Here's the code -  forgive my beginner's ways.  I've only been in Windows for 5 months...

      static PRINTDLG pd ;
      ABORTPRC     lpfnAbortProc ;
      BOOL         bError = FALSE ;
      FARPROC      lpfnPrintDlgProc ;
      RECT         rect ;
      HPEN         hBrush ;
      HGLOBAL      hGlobalMemory;
      LPDEVMODE    dmp;
      HANDLE      hlib;
      EDMPROC     fp;
      WORD        bytes;

      static char     szSpMsg [] = "GradeMaster Graph Printing";
      static char     ProfileString[256];
      static char     *DeviceName;
      static char     *DriverName;
      static char     *PortName;
      static char     DriverFormat[] = "%s.DRV";

      char        *tmp, str[128];
      short       xPage, yPage ;

           
      errz=2;

   // get printer device type

    GetProfileString( "Windows", "Device", "", ProfileString,      256);

   //Get Device Name

    DeviceName = ProfileString;

    tmp = ProfileString;
    while(1)
     {
      if( *tmp == ',' )
       {
        *tmp = 0;
        tmp++;
        break;
       }

      if( !(*tmp) )
       {
        DeviceName[0] = 0;
        MessageBox(NULL,"Bad DeviceName","", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
        return( NULL );
       }
        tmp++;
     }

    //Get DriverName
     
    DriverName = tmp;
    while( 1 )
     {

      if(*tmp == ',')
       {
        *tmp = 0;
        tmp++;
        break;
       }

      if(!(*tmp) )
       {
        DeviceName[0] = 0;
        MessageBox(NULL,"Bad DriverName","", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
        return( NULL );
       }

       tmp++;
     }

    if(!(*tmp))
     {
      DeviceName[0] = 0;
      MessageBox(NULL,"Bad PortName","", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
      return( NULL );
     }

   //Thus PortName    

    PortName = tmp;

   //Allocate memory for DEVMODE structure
       
    if (NULL==(hGlobalMemory = GlobalAlloc(GHND, sizeof (DEVMODE))))
     {  
      MessageBox(NULL,"Cannot Allocate Global Memory","", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
      return(FALSE);
     }

    if(NULL==(dmp = (LPDEVMODE) GlobalLock (hGlobalMemory)))
     {  
      MessageBox(NULL,"Cannot Lock Global Memory","", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
      return(FALSE);
     }

   //get Address of Driver

    sprintf( str, DriverFormat, DriverName );
    hlib = LoadLibrary( str );

    if( hlib >= 32 )
     {
      fp = GetProcAddress( hlib, "EXTDEVICEMODE" );
      FreeLibrary( hlib );
     }
    else
     {
       MessageBox(NULL,"No EXTDEVICEMODE...","", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
       GlobalUnlock(hGlobalMemory);
       GlobalFree(hGlobalMemory);
       return (FALSE);
     }    
       
  //use EXTDEVICEMODE to get Printer data size

    bytes = fp( NULL, hlib, (LPDEVMODE) NULL, (LPSTR) DeviceName,
              (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, 0);

  //allocate memory for string kludge
 
    PrinterData = malloc(bytes);

  //use EXTDEVICEMODE to get Printer data for string kludge (because hGlobalMemory shows no data)
 
    bytes = fp( NULL, hlib, (LPDEVMODE) PrinterData, (LPSTR) DeviceName,
              (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DM_OUT_BUFFER);

  //use EXTDEVICEMODE to get Printer data for hGlobalMemory

    bytes = fp( NULL, hlib, (LPDEVMODE) hGlobalMemory, (LPSTR) DeviceName,
              (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DM_OUT_BUFFER);

    FreeLibrary( hlib );

  /*
     set DEVMODE variables to landscape - a kludge that works with a good Printer Driver,
                                          but not with a substitute (Laser4 for Laser5SI)
  */

    strcpy(dmp->dmDeviceName,PrinterData);
    dmp->dmSpecVersion=NULL;
    dmp->dmDriverVersion=NULL;
    dmp->dmSize=NULL;
    dmp->dmDriverExtra=NULL;
    dmp->dmFields=DM_ORIENTATION;
    dmp->dmOrientation=DMORIENT_LANDSCAPE;
    dmp->dmPaperSize=NULL;
    dmp->dmPaperLength=NULL;
    dmp->dmPaperWidth=NULL;
    dmp->dmScale=NULL;
    dmp->dmCopies=NULL;
    dmp->dmDefaultSource=NULL;
    dmp->dmPrintQuality=NULL;
    dmp->dmColor=NULL;
    dmp->dmDuplex=NULL;
    dmp->dmYResolution=NULL;
    dmp->dmTTOption=NULL;

  //set Print Dialog variables to DEVMODE

     pd.lStructSize         = sizeof (PRINTDLG);
     pd.hwndOwner           = hwnd;
     pd.hDevMode            = hGlobalMemory;
     pd.hDevNames           = NULL;
     pd.hDC                 = NULL;
     pd.Flags               = PD_DISABLEPRINTTOFILE | PD_ALLPAGES | PD_COLLATE | PD_RETURNDC;
     pd.nFromPage           = 0 ;
     pd.nToPage             = 0 ;
     pd.nMinPage            = 0 ;
     pd.nMaxPage            = 0 ;
     pd.nCopies             = 1 ;
     pd.hInstance           = NULL ;
     pd.lCustData           = 0L ;
     pd.lpfnPrintHook       = NULL ;
     pd.lpfnSetupHook       = NULL ;
     pd.lpPrintTemplateName = NULL ;
     pd.lpSetupTemplateName = NULL ;
     pd.hPrintTemplate      = NULL ;
     pd.hSetupTemplate      = NULL ;

   //start Dialog box

     if (!PrintDlg (&pd))
      {
       GlobalUnlock(hGlobalMemory);
       GlobalFree(hGlobalMemory);
       free(PrinterData);
       errz=0;
       return errz;
      }


0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
nietodCommented:
This is a little out of my area of expertise,  but one thing I see is that you seem to free the printer driver dll before you use it.  You do.

      fp = GetProcAddress( hlib, "EXTDEVICEMODE" );
      FreeLibrary( hlib );

The free library should unload the driver so fp is no longer valid.  Then later on you use fp.
0
 
zilleskAuthor Commented:
nietod - I took out the freelibrary() right after fp (that's what I get for copying sample code), but when I put in

MessageBox(NULL,dmp->dmDeviceName,"", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);

all I get is a blank. It still works with the PrinterData string kludge, otherwise not - and when I try to access DEVMODE member structures with dmp.dmDeviceName, I get "must be a structure or union" error.  I can't figure out how to declare a DEVMODE structure (devmode dm) and then access the memory with GlobalAlloc and GlobalLock functions (which Help seems to say you have to do).


0
 
zilleskAuthor Commented:
Adjusted points to 150
0
 
nietodCommented:
I don't see where you are using the DOVMODE structure.

However, you can declare it as a local structure.  Like

DEVMODE DM = {  initialization stuff    };

That should be much easier.  Note that the size inside the structure (dmSize) needs to be initialized,  You are setting it to 0, it should be sizeof(DEVMODE).  

0
 
nietodCommented:
Now I see what you mean

This works
 bytes = fp( NULL, hlib, (LPDEVMODE) PrinterData, (LPSTR) DeviceName,
                   (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DM_OUT_BUFFER);

but this doesn't.
  bytes = fp( NULL, hlib, (LPDEVMODE) hGlobalMemory, (LPSTR) DeviceName,
                   (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DM_OUT_BUFFER);

The problem is the 3rd parameter is hGlobalMemory.  It should be a pointer (dmp) not a memory handle.
0
 
nietodCommented:
I was confused because I didn't realize you had working and non-working code intermixed.  I also couldn;t see where you were using the DEVMODE structure.  (That was the bug. but I didn't know that.)

However, unless the documentation says that the DEVMODE needs to be allcoated in global memory (I only have 32 bit documentation.)  You don't need to use GlobalAlloc and GlobalLock and all that stuff.  Just declare the DEVMODE structure locally and pass a pointer to it, like

DEVMODE DM;

  bytes = fp( NULL, hlib, &DM, (LPSTR) DeviceName,
                   (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DM_OUT_BUFFER);
0
 
zilleskAuthor Commented:
nietod -

Unfortunately, that's what the docs do say -

Identifies a movable global memory object that contains a DEVMODE structure. Before the PrintDlg function is called, the members in this structure may contain data used to initialize the dialog box controls. When the PrintDlg function returns, the members in this structure specify the state of each of the dialog box controls.

I have already tired dmp as the variable (got a GPF in the driver) and then tried it with localalloc; didn't work.

When I try to do the DEVMODE dm, I can't allocate global memory for dm (as I did local mem in simple old DOS C) .

struct DEVMODE dm;
dm=calloc(1,sizeof(DEVMODE));
dm.dmOrientation=DMORIENT_LANDSCAPE;

Simple, but Not!
0
 
nietodCommented:
Okay if it has to be movable, then do allocate it the way you've been doing.

However, your are still passing the wrong parameter.  You are passing a handle to the procedure that fp points to.  I don't have docs for that procedure.  But the case that works (string) you pass a pointer to memory and the case that doesn't you pass a handle.  It seems to me like the procedure expects a pointer, not a handle.
0
 
NullTerminatorCommented:
It been a while since my 3.11 days,  but here's a shot in the dark.
I use VC 4.x with MFC.  in the print function for the view the framework passes a printinfo stucture.  pInfo in my case.  it has a pointer to a PrintDialog, m_pd.  Printdialog can be called without its diaplaying an interface. The code below is all I need to force the orientation on whatever printer the user has currently set up. If you are using some other framework, perhaps you can modify it..

// force Portrait Mode code excerpted from
void CMyView:OnPreparePrinting(CPrintInfo* pInfo) // virtual mfc function
{
// other program lines

// get current device info and populate a printdialog object
      AfxGetApp()->GetPrinterDeviceDefaults( &(pInfo->m_pPD->m_pd ));
// capture device mode -- no allocation only deallocation when done
      LPDEVMODE DevMode = pInfo->m_pPD->GetDevMode();
// do it
      DevMode->dmOrientation = DMORIENT_PORTRAIT;
// tell system which data is valid
      DevMode->dmFields |= DM_ORIENTATION;
// leggo
      ::GlobalFree(DevMode);
// other program lines
return DoPreparePrinting(pInfo); // call base class
}   // end of DoPreparePrinting(pInfo);


0
 
zilleskAuthor Commented:
NullTerminator -

there goes my learning curve - I don't have a clue about MFC or C++.  You're doing what I need to do with functions I don't have - the equivalents for Win311 are pretty archaic.

Nietod - I tried playing with DEVMODE dm, using your

DEVMODE DM;

  bytes = fp( NULL, hlib, &DM, (LPSTR) DeviceName,
                   (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DM_OUT_BUFFER);

then I do

    dm.dmOrientation=DMORIENT_LANDSCAPE;
    dm.dmFields=DM_ORIENTATION;
    dmp=&DM;

and I get a dialog - but it doesn't change DM.dmOrientation in the Setup (although when I dump  DM.dmOrientation and dmp->dmOrientation, they both show DMORIENT_LANDSCAPE).

And (of course) when I exit the function, I get a GPF and crash, I figure because DM has no memory space allocated.
I guess what I need to do is declare the DEVMODE structure and somehow allocate global memory for it, or point it to dmp.

 
0
 
nietodCommented:
I said that was a possible improvement if the DEVMODE does not have to be globally allocated.  You said you must have the DEVMODE structure globally allocated.  so don't declare it locally, like

DECMODE DM;

Don't do that.  Allocate it with GlobalAlloc if it has to be in global memory.

However the problem is that you are passing a handle to this global memory when you need to pass a pointer.  You do

 bytes = fp( NULL, hlib, (LPDEVMODE) hGlobalMemory, (LPSTR) DeviceName,
                        (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, _OUT_BUFFER);

That is wrong.  The 3rd parameter shoudl be a pointer to the locked global memory, like

bytes = fp( NULL, hlib, dmp, (LPSTR) DeviceName,
                        (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, _OUT_BUFFER);
0
 
zilleskAuthor Commented:
nietod -

When I do

bytes = fp( NULL, hlib, dmp, (LPSTR) DeviceName,
                        (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, _OUT_BUFFER);

I do not get a dialog box and the program crashes with this error:

WNPRGRAM caused a general protection fault
in module UNIDRV.DLL at 0001:00000088.

I have tried

bytes = fp( NULL, hlib, (LPDEVMODE) dmp, (LPSTR) DeviceName,
                        (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, _OUT_BUFFER);

with the same results.


The funny thing is that when I put in dm

    bytes = fp( NULL, hlib, &dm, (LPSTR) DeviceName,
              (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DM_OUT_BUFFER);

    dmp=&dm;

    sprintf(txt,"%s",dmp->dmDeviceName);
    MessageBox(NULL,txt,"", MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);

    dmp->dmOrientation=DMORIENT_LANDSCAPE;
    dmp->dmFields=DM_ORIENTATION;

I get data and a dialog box (where DM_ORIENTATION doesn't change as I want it to),  but then it crashes on exit from function with this error:

WNPRGRAM  caused a general protection fault
in module WNPRGRAM.EXE at 0002:0000938a.


0
 
zilleskAuthor Commented:
Adjusted points to 195
0
 
nietodCommented:
answer coming.
0
 
nietodCommented:
Reading your code is a nightmare.  You should switch to C++ and windows.32.  It will make my life easier. :-)

The problem appears to be the amount of memory you are allocating.  With your "string kludge" your are calling the function to ask it how much memory to allocate.  See first you specify NULL in the 3rd parameter, which tells it the returnt he number of bytes it wants, like

  bytes = fp( NULL, hlib, (LPDEVMODE) NULL, (LPSTR) DeviceName,
                   (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, 0);

Then you allocate the number of bytes it wants.

         PrinterData = malloc(bytes);

finally you specfy the memory of the size it suggested.
       
         bytes = fp( NULL, hlib, (LPDEVMODE) PrinterData, (LPSTR) DeviceName,
                   (LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DM_OUT_BUFFER);

You need to do that with the globally allocated memory as well.  You need to get the size to be allocated before you allocate the memory.  Does this make sense?


0
 
zilleskAuthor Commented:
nietod -

Makes sense to me, but...

I globally allocated the size as 'bytes', ran the prog and the PC froze and had to be rebooted.  

yes, my code is nightmarish (at least when it doesn't work).  I'm going to W95 after this goes - that learning curve ought to be steep -  but in the meantime... arrrrghh
0
 
nietodCommented:
Post that code.  That code is closer that what you had before.  do you have any documentation on this function you are calling (EXTDEVMODE).  I don't because I only have 32 bit docs.  If you have some 16 bit docs can you post it or if it is too long e-mail it to me at nietod@theshop.net.

By the way you won't find win32 that big a change.  In general, things get better, not worse, and there won't be too much to learn.

If you can switch to C++, that is a BIG change, but one that I recommend highly.  But when you make the change you can start using it like C and slowly add in C++ features as you learn them.
0
 
nietodCommented:
Thanks for the docs.  Things are making more sense.  Can you post your current code or e-mail it to me?
0
 
zilleskAuthor Commented:
nietod - you hit the nail on the head - now I'm waiting to give a grade...
0
 
zilleskAuthor Commented:
nietod -

I'll wait, go home, and try it out on that printer driver.  If that's OK, it's got to be an 'A'.

thanks again -  K
0
 
zilleskAuthor Commented:
nietod -

Thanks for bearing with me.  It works like a charm at home, too. Perhaps I'll have some C++ questions in 4 months (I may have to start buyng points)...
0
 
nietodCommented:
Great I can't hardly wait :-)  

I looked over the code you sent and didn't see any other problems.  in 4 months you should earn 600 points or so anyways.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.