Click here to Skip to main content
15,867,833 members
Articles / Desktop Programming / MFC
Article

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

Rate me:
Please Sign up or sign in to vote.
3.08/5 (22 votes)
20 Nov 2005 154.4K   21   45
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


Written By
Web Developer
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionChange more than one setting at once Pin
camposartur2-Jul-19 15:28
camposartur2-Jul-19 15:28 
QuestionChanging the Paper Handling --> Default Paper Size Programatically of Printer Device Settings... Pin
vamsi27105-Mar-17 20:11
vamsi27105-Mar-17 20:11 
QuestionChange dmScale Pin
Creamcatcher9-Feb-13 22:54
Creamcatcher9-Feb-13 22:54 
GeneralMy vote of 3 Pin
sabarin_wipro27-Dec-12 19:54
sabarin_wipro27-Dec-12 19:54 
GeneralRe: My vote of 3 Pin
AlexEvans28-Dec-12 10:38
AlexEvans28-Dec-12 10:38 
GeneralRe: My vote of 3 Pin
sabarin_wipro1-Jan-13 2:03
sabarin_wipro1-Jan-13 2:03 
GeneralProblem with custom page size Pin
jim_sc17-Sep-09 3:00
jim_sc17-Sep-09 3:00 
GeneralHaving a little issue with SetPrinter and PRINTER_ALL_ACCESS Pin
Member 345539814-Sep-08 16:27
Member 345539814-Sep-08 16:27 
GeneralRe: Having a little issue with SetPrinter and PRINTER_ALL_ACCESS Pin
AlexEvans14-Sep-08 17:55
AlexEvans14-Sep-08 17:55 
GeneralIncorrect use of delete Pin
Hans Dietrich11-Sep-08 19:28
mentorHans Dietrich11-Sep-08 19:28 
GeneralRe: Incorrect use of delete Pin
AlexEvans11-Sep-08 21:55
AlexEvans11-Sep-08 21:55 
QuestionGetDefaultPrinter Missing! Pin
gjr17-Jul-07 19:30
gjr17-Jul-07 19:30 
AnswerRe: GetDefaultPrinter Missing! Pin
AlexEvans22-Jul-07 11:59
AlexEvans22-Jul-07 11:59 
AnswerRe: GetDefaultPrinter Missing! Pin
gjr22-Jul-07 17:22
gjr22-Jul-07 17:22 
GeneralCustom Paper Size Pin
Alexis Blaze26-Jun-07 6:30
Alexis Blaze26-Jun-07 6:30 
GeneralRe: error message Pin
mla1549-Aug-06 10:48
mla1549-Aug-06 10:48 
GeneralRe: error message Pin
AlexEvans9-Aug-06 15:51
AlexEvans9-Aug-06 15:51 
QuestionHow to detect whether a printer is physically connected Pin
vijay kumar T17-Jan-06 7:54
vijay kumar T17-Jan-06 7:54 
QuestionHow to change the tray for a network Printer Pin
vijay kumar T12-Jan-06 8:48
vijay kumar T12-Jan-06 8:48 
AnswerHow to change the tray for a network Printer Pin
AlexEvans12-Jan-06 14:26
AlexEvans12-Jan-06 14:26 
GeneralRe: How to change the tray for a network Printer Pin
vijay kumar T13-Jan-06 5:15
vijay kumar T13-Jan-06 5:15 
QuestionRe: How to change the tray for a network Printer Pin
vijay kumar T13-Jan-06 5:18
vijay kumar T13-Jan-06 5:18 
QuestionSetPrinter() failed on network printer Pin
leojose7-Dec-05 23:51
leojose7-Dec-05 23:51 
AnswerRe: SetPrinter() failed on network printer Pin
AlexEvans8-Dec-05 8:55
AlexEvans8-Dec-05 8:55 
NewsRe: SetPrinter() failed on network printer Pin
leojose8-Dec-05 18:39
leojose8-Dec-05 18:39 

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

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