Click here to Skip to main content
Click here to Skip to main content

Set up/change printer orientation and select paper type/size

, 20 Nov 2005
Rate this:
Please Sign up or sign in to vote.
Changing printer orientation and paper type at run time.

Introduction

Well.. it has been a long trip since I first found the excellent work “ReportGenrator” published by Johan Rosengren. Not only is it a very helpful set of tools, but I must use this opportunity to thank Johan for his ongoing support, feedback, and prompt response to many of my questions along the way.

Inspired by this project, and finding my own challenges, I had to resolve a few other issues along the way, two that are no doubt “Generic” type issues:

  1. Changing the printer orientation at run time – from Portrait to Landscape and back.
  2. Setting up the paper size / type programmatically.

The following two static functions are aimed exactly at doing that.

You can call SetDefaultPrinterOrientation() like in the following example. The return value can be used to set the printer back to whatever it was set to, before making the call.

int OriginalOrientation = SetDefaultPrinterOrientation(DMORIENT_LANDSCAPE);
SetPaperType(DMPAPER_<st1:stockticker>ENV</st1:stockticker>_DL);

/* orientation selections */
#define DMORIENT_PORTRAIT 1
#define DMORIENT_LANDSCAPE 2

Those are defined in WinGdi.h, as are the various paper selections that can be used by the SetPaperType() function.

#include "winspool.h"

int SetDefaultPrinterOrientation(short dmOrientation)
{
    HANDLE hPrinter = NULL;
    DWORD dwNeeded = 0;
    PRINTER_INFO_2 *pi2 = NULL;
    DEVMODE *pDevMode = NULL;
    PRINTER_DEFAULTS pd;
    BOOL bFlag;
    LONG lFlag;
    LPTSTR pPrinterName = NULL;
    DWORD size;
    GetDefaultPrinter(NULL, &size);
    TCHAR* buffer = new TCHAR[size];
    if(GetDefaultPrinter(buffer, &size))
        pPrinterName = buffer;
    else
    {
        if(buffer != NULL)
            delete buffer;
        return 0;
    }
    // Open printer handle (on Windows NT, you need full-access because you
    // will eventually use SetPrinter)...
    ZeroMemory(&pd, sizeof(pd));
    pd.DesiredAccess = PRINTER_ALL_ACCESS;
    bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
    if (!bFlag || (hPrinter == NULL))
    {
        if(buffer != NULL)
            delete buffer;
        return 0;
    }
    // The first GetPrinter tells you how big the buffer should be in 
    // order to hold all of PRINTER_INFO_2. Note that this should fail with 
    // ERROR_INSUFFICIENT_BUFFER. If GetPrinter fails for any other reason 
    // or dwNeeded isn't set for some reason, then there is a problem...
    SetLastError(0);
    bFlag = GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
    if ((!bFlag) && (GetLastError() != 
             ERROR_INSUFFICIENT_BUFFER) || (dwNeeded == 0))
    {
        ClosePrinter(hPrinter);
        if(buffer != NULL)
            delete buffer;
        return 0;
    }
    // Allocate enough space for PRINTER_INFO_2...
    pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
    if (pi2 == NULL)
    {
        ClosePrinter(hPrinter);
        if(buffer != NULL)
            delete buffer;
        return 0;
    }
    // The second GetPrinter fills in all the current settings, so all you
    // need to do is modify what you're interested in...
    bFlag = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
    if (!bFlag)
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if(buffer != NULL)
            delete buffer;
        return 0;
    }
    // If GetPrinter didn't fill in the DEVMODE,
    // try to get it by calling DocumentProperties...
    if (pi2->pDevMode == NULL)
    {
        dwNeeded = DocumentProperties(NULL, hPrinter, 
                         pPrinterName,NULL, NULL, 0);
        if (dwNeeded <= 0)
        {
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            if(buffer != NULL)
                delete buffer;
            return 0;
        }
        pDevMode = (DEVMODE *)GlobalAlloc(GPTR, dwNeeded);
        if (pDevMode == NULL)
        {
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            if(buffer != NULL)
                delete buffer;
            return 0;
        }
        lFlag = DocumentProperties(NULL, hPrinter, 
                pPrinterName, pDevMode, NULL,DM_OUT_BUFFER);
        if (lFlag != IDOK || pDevMode == NULL)
        {
            GlobalFree(pDevMode);
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            if(buffer != NULL)
                delete buffer;
            return 0;
        }
        pi2->pDevMode = pDevMode;
    }
    // Driver is reporting that it doesn't support this change...
    if (!(pi2->pDevMode->dmFields & DM_ORIENTATION))
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if (pDevMode)
            GlobalFree(pDevMode);
        if(buffer != NULL)
            delete buffer;
        return 0;
    }
    // Specify exactly what we are attempting to change...
    pi2->pDevMode->dmFields = DM_ORIENTATION;
    // Make note of the current Orientation setting
    // If the functions works, return it to the calling program
    // So that, the application can set it back to whatever
    // it used to be before the call
    int OriginalOrientation = pi2->pDevMode->dmOrientation;
    // Now, change it to whatever was requested by the calling application
    pi2->pDevMode->dmOrientation = dmOrientation;
    // Do not attempt to set security descriptor...
    pi2->pSecurityDescriptor = NULL;
    // Make sure the driver-dependent part of devmode is updated...
    lFlag = DocumentProperties(NULL, hPrinter, pPrinterName, 
            pi2->pDevMode, pi2->pDevMode, 
            DM_IN_BUFFER | DM_OUT_BUFFER);
    if (lFlag != IDOK)
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if (pDevMode)
            GlobalFree(pDevMode);
        if(buffer != NULL)
            delete buffer;
        return 0;
    }
    // Update printer information...
    bFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);
    if (!bFlag)
    // The driver doesn't support, or it is unable to make the change...
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if (pDevMode)
            GlobalFree(pDevMode);
        if(buffer != NULL)
            delete buffer;
        return 0;
    }
    // Tell other apps that there was a change...
    SendMessageTimeout(HWND_BROADCAST, WM_DEVMODECHANGE, 0L, 
             (LPARAM)(LPCSTR)pPrinterName, SMTO_NORMAL, 1000, NULL);
    // Clean up...
    if (pi2)
        GlobalFree(pi2);
    if (hPrinter)
        ClosePrinter(hPrinter);
    if (pDevMode)
        GlobalFree(pDevMode);
    if(buffer != NULL)
        delete buffer;
    return OriginalOrientation;
}

// It seems that you can’t change more than one attribute
// at a time, hence I needed to
// create two separate functions, on to change orientation,
// and the other to select /
// change the paper type for my specific task
BOOL SetPaperType(short dmPaperSize)
{
    HANDLE hPrinter = NULL;
    DWORD dwNeeded = 0;
    PRINTER_INFO_2 *pi2 = NULL;
    DEVMODE *pDevMode = NULL;
    PRINTER_DEFAULTS pd;
    BOOL bFlag;
    LONG lFlag;
    LPTSTR pPrinterName = NULL;
    DWORD size;
    GetDefaultPrinter(NULL, &size);
    TCHAR* buffer = new TCHAR[size];
    if(GetDefaultPrinter(buffer, &size))
        pPrinterName = buffer;
    else
    {
        if(buffer != NULL)
            delete buffer;
        return FALSE;
    }
    // Open printer handle (on Windows NT,
    // you need full-access because you
    // will eventually use SetPrinter)...
    ZeroMemory(&pd, sizeof(pd));
    pd.DesiredAccess = PRINTER_ALL_ACCESS;
    bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
    if (!bFlag || (hPrinter == NULL))
    {
        if(buffer != NULL)
            delete buffer;
        return FALSE;
    }
    // The first GetPrinter tells you how big the buffer should be in 
    // order to hold all of PRINTER_INFO_2. Note that this should fail with 
    // ERROR_INSUFFICIENT_BUFFER. If GetPrinter fails for any other reason 
    // or dwNeeded isn't set for some reason, then there is a problem...
    SetLastError(0);
    bFlag = GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
    if ((!bFlag) && (GetLastError() != 
             ERROR_INSUFFICIENT_BUFFER) || (dwNeeded == 0))
    {
        ClosePrinter(hPrinter);
        if(buffer != NULL)
            delete buffer;
        return FALSE;
    }
    // Allocate enough space for PRINTER_INFO_2...
    pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
    if (pi2 == NULL)
    {
        ClosePrinter(hPrinter);
        if(buffer != NULL)
            delete buffer;
        return FALSE;
    }
    // The second GetPrinter fills in all the current settings, so all you
    // need to do is modify what you're interested in...
    bFlag = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
    if (!bFlag)
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if(buffer != NULL)
            delete buffer;
        return FALSE;
    }
    // If GetPrinter didn't fill in the DEVMODE,
    // try to get it by calling DocumentProperties...
    if (pi2->pDevMode == NULL)
    {
        dwNeeded = DocumentProperties(NULL, hPrinter, 
                         pPrinterName,NULL, NULL, 0);
        if (dwNeeded <= 0)
        {
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            if(buffer != NULL)
                delete buffer;
            return FALSE;
        }
        pDevMode = (DEVMODE *)GlobalAlloc(GPTR, dwNeeded);
        if (pDevMode == NULL)
        {
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            if(buffer != NULL)
                delete buffer;
            return FALSE;
        }
        lFlag = DocumentProperties(NULL, hPrinter, 
                     pPrinterName, pDevMode, NULL,DM_OUT_BUFFER);
        if (lFlag != IDOK || pDevMode == NULL)
        {
            GlobalFree(pDevMode);
            GlobalFree(pi2);
            ClosePrinter(hPrinter);
            if(buffer != NULL)
                delete buffer;
            return FALSE;
        }
        pi2->pDevMode = pDevMode;
    }
    // Specify exactly what we are attempting to change...
    pi2->pDevMode->dmFields = DM_PAPERSIZE; 
    // Now, change it to whatever was requested by the calling application
    pi2->pDevMode->dmPaperSize = dmPaperSize;
    // Do not attempt to set security descriptor...
    pi2->pSecurityDescriptor = NULL;
    // Make sure the driver-dependent part of devmode is updated...
    lFlag = DocumentProperties(NULL, hPrinter, pPrinterName, 
            pi2->pDevMode, pi2->pDevMode, 
            DM_IN_BUFFER | DM_OUT_BUFFER);
    if (lFlag != IDOK)
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if (pDevMode)
            GlobalFree(pDevMode);
        if(buffer != NULL)
            delete buffer;
        return FALSE;
    }
    // Update printer information...
    bFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);
    if (!bFlag)
    // The driver doesn't support, or it is unable to make the change...
    {
        GlobalFree(pi2);
        ClosePrinter(hPrinter);
        if (pDevMode)
            GlobalFree(pDevMode);
        if(buffer != NULL)
            delete buffer;
        return FALSE;
    }
    // Tell other apps that there was a change...
    SendMessageTimeout(HWND_BROADCAST, WM_DEVMODECHANGE, 0L, 
             (LPARAM)(LPCSTR)pPrinterName, SMTO_NORMAL, 1000, NULL);
    // Clean up...
    if (pi2)
        GlobalFree(pi2);
    if (hPrinter)
        ClosePrinter(hPrinter);
    if (pDevMode)
        GlobalFree(pDevMode);
    if(buffer != NULL)
        delete buffer;
    return TRUE;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

AlexEvans
Web Developer
Australia Australia
No Biography provided

Comments and Discussions

 
QuestionChange dmScale [modified] PinmemberMember 15754029-Feb-13 22:54 
GeneralMy vote of 3 Pinmembersabarin_wipro27-Dec-12 19:54 
GeneralRe: My vote of 3 PinmemberAlexEvans28-Dec-12 10:38 
GeneralRe: My vote of 3 [modified] Pinmembersabarin_wipro1-Jan-13 2:03 
GeneralProblem with custom page size Pinmemberjim_sc17-Sep-09 3:00 
GeneralHaving a little issue with SetPrinter and PRINTER_ALL_ACCESS PinmemberMember 345539814-Sep-08 16:27 
GeneralRe: Having a little issue with SetPrinter and PRINTER_ALL_ACCESS PinmemberAlexEvans14-Sep-08 17:55 
GeneralIncorrect use of delete PinmvpHans Dietrich11-Sep-08 19:28 
GeneralRe: Incorrect use of delete PinmemberAlexEvans11-Sep-08 21:55 
QuestionGetDefaultPrinter Missing! Pinmembergjr17-Jul-07 19:30 
AnswerRe: GetDefaultPrinter Missing! PinmemberAlexEvans22-Jul-07 11:59 
AnswerRe: GetDefaultPrinter Missing! Pinmembergjr22-Jul-07 17:22 
GeneralCustom Paper Size PinmemberAlexis Blaze26-Jun-07 6:30 
GeneralRe: error message Pinmembermla1549-Aug-06 10:48 
GeneralRe: error message PinmemberAlexEvans9-Aug-06 15:51 
QuestionHow to detect whether a printer is physically connected Pinmembervijay kumar T17-Jan-06 7:54 
QuestionHow to change the tray for a network Printer Pinmembervijay kumar T12-Jan-06 8:48 
AnswerHow to change the tray for a network Printer PinmemberAlexEvans12-Jan-06 14:26 
GeneralRe: How to change the tray for a network Printer Pinmembervijay kumar T13-Jan-06 5:15 
QuestionRe: How to change the tray for a network Printer Pinmembervijay kumar T13-Jan-06 5:18 
QuestionSetPrinter() failed on network printer Pinmemberleojose7-Dec-05 23:51 
AnswerRe: SetPrinter() failed on network printer PinmemberAlexEvans8-Dec-05 8:55 
NewsRe: SetPrinter() failed on network printer Pinmemberleojose8-Dec-05 18:39 
GeneralRe: SetPrinter() failed on network printer PinmemberAlexEvans8-Dec-05 20:32 
NewsRe: SetPrinter() failed on network printer Pinmemberleojose8-Dec-05 20:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141030.1 | Last Updated 20 Nov 2005
Article Copyright 2005 by AlexEvans
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid