Solved

Using DEVMODE Structure to change Orientation

Posted on 1998-06-17
25
644 Views
Last Modified: 2013-12-03
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?
0
Comment
Question by:zillesk
  • 13
  • 11
25 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 1408050
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
 

Author Comment

by:zillesk
ID: 1408051
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
 
LVL 22

Expert Comment

by:nietod
ID: 1408052
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
 

Author Comment

by:zillesk
ID: 1408053
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
 

Author Comment

by:zillesk
ID: 1408054
Adjusted points to 150
0
 
LVL 22

Expert Comment

by:nietod
ID: 1408055
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
 
LVL 22

Expert Comment

by:nietod
ID: 1408056
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
 
LVL 22

Expert Comment

by:nietod
ID: 1408057
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
 

Author Comment

by:zillesk
ID: 1408058
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
 
LVL 22

Expert Comment

by:nietod
ID: 1408059
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
 
LVL 3

Expert Comment

by:NullTerminator
ID: 1408060
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
 

Author Comment

by:zillesk
ID: 1408061
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
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 22

Expert Comment

by:nietod
ID: 1408062
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
 

Author Comment

by:zillesk
ID: 1408063
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
 

Author Comment

by:zillesk
ID: 1408064
Adjusted points to 195
0
 
LVL 22

Expert Comment

by:nietod
ID: 1408065
answer coming.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1408066
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
 

Author Comment

by:zillesk
ID: 1408067
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
 
LVL 22

Expert Comment

by:nietod
ID: 1408068
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
 
LVL 22

Expert Comment

by:nietod
ID: 1408069
Thanks for the docs.  Things are making more sense.  Can you post your current code or e-mail it to me?
0
 

Author Comment

by:zillesk
ID: 1408070
nietod - you hit the nail on the head - now I'm waiting to give a grade...
0
 
LVL 22

Accepted Solution

by:
nietod earned 190 total points
ID: 1408071
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
 

Author Comment

by:zillesk
ID: 1408072
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
 

Author Comment

by:zillesk
ID: 1408073
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
 
LVL 22

Expert Comment

by:nietod
ID: 1408074
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

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

28 Experts available now in Live!

Get 1:1 Help Now