views:

590

answers:

2

I've got an old app that I need to get to print in landscape mode. The documentation I've found says to get a DEVMODE structure, change a couple of fields, and put it back in. What I've got is:

    HANDLE printer_handle;
    LPHANDLE printer_handle_pointer(&printer_handle);
    OpenPrinter(printer_name.get(), printer_handle_pointer, NULL);
    size_t devmode_size = DocumentProperties(hWnd, printer_handle_pointer, printer_name.get(), NULL, NULL, 0);
    DEVMODE * devmode = reinterpret_cast<DEVMODE *>(new char[devmode_size]);
    DocumentProperties(NULL, printer_handle_pointer, printer_name.get(), devmode, NULL, DM_OUT_BUFFER);
    devmode->dmSize = sizeof( DEVMODE);
    devmode->dmFields |= DM_ORIENTATION;
    devmode->dmOrientation = DMORIENT_LANDSCAPE;
    DocumentProperties(NULL, printer_handle_pointer, printer_name.get(), devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER);
    hdcPrint = CreateDC(NULL, printer_name.get(), NULL, devmode);

My current problem is that the first DocumentProperties (the one that returns the size of the DEVMODE structure) is returning a -1 (actually the unsigned equivalent), signifying an error condition. This happens in both Debug and Release mode (one report I saw on the web had this problem in Debug but not Release). The printer_name.get() is valid, but I don't know how to check the hWnd or printer_handle_pointer for correctness in the debugger.

So, I'd like it if somebody could tell me what I'm doing wrong, or how to diagnose it better, or how to tell if the handles are valid and point to valid information, I'd appreciate it.

I'm using VS 2008SP1 on Vista Business SP1, if that makes any difference. The original app was written with an earlier version of VS on some version of XP.

+2  A: 

Have you posted the real code?

Also, take a look at the DocumentProperties function signature:

LONG DocumentProperties(
     __in   HWND hWnd,
     __in   HANDLE hPrinter,         
     __in   LPTSTR pDeviceName,
     __out  PDEVMODE pDevModeOutput,
     __in   PDEVMODE pDevModeInput,
     __in   DWORD fMode

The third parameter takes a HANDLE and not a pointer to a HANDLE (or LPHANDLE) as you have in your code:

DocumentProperties(NULL, 
                   printer_handle_pointer, /* <--- ? */
                   printer_name.get(), 
                   devmode, 
                   NULL, 
                   DM_OUT_BUFFER);

Use instead:

DocumentProperties(NULL, 
                   printer_handle, /* <--- ? */
                   printer_name.get(), 
                   devmode, 
                   NULL, 
                   DM_OUT_BUFFER);

Take a look at this sample code to modify Devmode using DocumentProperties function.

I typically use GetPrinterW to get a PRINTER_INFO_2W structure. The pDevMode member returns you the devmode. I have had some luck using this devmode.

dirkgently
Thanks for the pointer, but the GetPrinter() technique worked no better for me.
David Thornley
Many thanks. That nailed it.
David Thornley
A: 

From the Microsoft documentation for DocumentProperties:

To make changes to print settings that are local to an application, an application should follow these steps:

  1. Get the number of bytes required for the full DEVMODE structure by calling DocumentProperties and specifying zero in the fMode parameter.
  2. Allocate memory for the full DEVMODE structure.
  3. Get the current printer settings by calling DocumentProperties. Pass a pointer to the DEVMODE structure allocated in Step 2 as the pDevModeOutput parameter and specify the DM_OUT_BUFFER value.
  4. Modify the appropriate members of the returned DEVMODE structure and indicate which members were changed by setting the corresponding bits in the dmFields member of the DEVMODE.
  5. Call DocumentProperties and pass the modified DEVMODE structure back as both the pDevModeInput and pDevModeOutput parameters and specify both the DM_IN_BUFFER and DM_OUT_BUFFER values (which are combined using the OR operator).The DEVMODE structure returned by the third call to DocumentProperties can be used as an argument in a call to the CreateDC function.

It looks like you're missing step 1, which may be why your first call to DocumentProperties fails.

In my own program I also set the page size, swapping length and width. This is for a special small label printer with a custom paper size though, I don't know if a more garden variety printer would require this.

double width = 8.5;
double height = 11.0;
devmode.dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH;
devmode.dmOrientation = DMORIENT_LANDSCAPE;
devmode.dmPaperSize = DMPAPER_USER;
devmode.dmPaperLength = (short)(width * 25.4 * 10);
devmode.dmPaperWidth = (short)(height * 25.4 * 10);
Mark Ransom
Actually, I have step 1 in there (the line begins "size_t devmode_size"), and the problem is that devmode_size (the returned value) is not accurate. I was apparently unclear.
David Thornley
I changed the question slightly, to make it more clear. Hope this helps.
David Thornley
My bad, I need to read a little better.
Mark Ransom