Click here to Skip to main content
6,822,613 members and growing! (19,685 online)
Email Password   helpLost your password?
Desktop Development » Printing » General     Intermediate

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

By AlexEvans

Changing printer orientation and paper type at run time.
VC6, VC7, VC7.1Win2K, WinXP, Visual-Studio, MFC, Dev
Posted:20 Nov 2005
Views:62,848
Bookmarked:17 times
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
20 votes for this article.
Popularity: 3.96 Rating: 3.04 out of 5
7 votes, 35.0%
1

2
2 votes, 10.0%
3
2 votes, 10.0%
4
9 votes, 45.0%
5

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

About the Author

AlexEvans


Member

Occupation: Web Developer
Location: Australia Australia

Other popular Printing articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 39 (Total in Forum: 39) (Refresh)FirstPrevNext
GeneralProblem with custom page size Pinmemberjim_sc4:00 17 Sep '09  
GeneralHaving a little issue with SetPrinter and PRINTER_ALL_ACCESS PinmemberMember 345539817:27 14 Sep '08  
GeneralRe: Having a little issue with SetPrinter and PRINTER_ALL_ACCESS PinmemberAlexEvans18:55 14 Sep '08  
GeneralIncorrect use of delete PinmvpHans Dietrich20:28 11 Sep '08  
GeneralRe: Incorrect use of delete PinmemberAlexEvans22:55 11 Sep '08  
QuestionGetDefaultPrinter Missing! Pinmembergjr20:30 17 Jul '07  
AnswerRe: GetDefaultPrinter Missing! PinmemberAlexEvans12:59 22 Jul '07  
AnswerRe: GetDefaultPrinter Missing! Pinmembergjr18:22 22 Jul '07  
GeneralCustom Paper Size PinmemberAlexis Blaze7:30 26 Jun '07  
GeneralRe: error message Pinmembermla15411:48 9 Aug '06  
GeneralRe: error message PinmemberAlexEvans16:51 9 Aug '06  
QuestionHow to detect whether a printer is physically connected Pinmembervijay kumar T8:54 17 Jan '06  
GeneralHow to change the tray for a network Printer Pinmembervijay kumar T9:48 12 Jan '06  
GeneralHow to change the tray for a network Printer PinmemberAlexEvans15:26 12 Jan '06  
GeneralRe: How to change the tray for a network Printer Pinmembervijay kumar T6:15 13 Jan '06  
QuestionRe: How to change the tray for a network Printer Pinmembervijay kumar T6:18 13 Jan '06  
QuestionSetPrinter() failed on network printer Pinmemberleojose0:51 8 Dec '05  
AnswerRe: SetPrinter() failed on network printer PinmemberAlexEvans9:55 8 Dec '05  
NewsRe: SetPrinter() failed on network printer Pinmemberleojose19:39 8 Dec '05  
GeneralRe: SetPrinter() failed on network printer PinmemberAlexEvans21:32 8 Dec '05  
NewsRe: SetPrinter() failed on network printer Pinmemberleojose21:41 8 Dec '05  
GeneralRe: SetPrinter() failed on network printer Pinmemberleojose5:25 15 Dec '05  
GeneralRe: SetPrinter() failed on network printer PinmemberAlexEvans10:31 15 Dec '05  
GeneralRe: SetPrinter() failed on network printer PinmemberAlexEvans11:30 15 Dec '05  
GeneralRe: SetPrinter() failed on network printer Pinmemberleojose22:23 2 Jan '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

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

PermaLink | Privacy | Terms of Use
Last Updated: 20 Nov 2005
Editor: Smitha Vijayan
Copyright 2005 by AlexEvans
Everything else Copyright © CodeProject, 1999-2010
Web18 | Advertise on the Code Project