HOWTO: Obtaining the DEVMODE and DEVNAMES Structures

Last reviewed: November 24, 1997
Article ID: Q166129
The information in this article applies to:
  • The Microsoft Foundation Classes (MFC) included with: - Microsoft Visual C++, 32-bit Editions, versions 4.0, 4.1, 4.2, 4.2b,

         5.0
    

SUMMARY

You need the DEVMODE and DEVNAMES structures to specify a printer in an MFC application when you programmatically print to a non-default (network or secondary) printer. They can be manually constructed using information obtained from the GetPrinter() printer API.

MORE INFORMATION

During a normal print operation in an MFC application, the print dialog box is displayed which allows you to select the printer you want to print to. The default printer displayed in the print dialog box is the default printer specified in the system. MFC stores the default printer of the application in the CWinApp::m_hDevMode and CWinApp::m_hDevNames protected data members. Because MFC initializes these variables to NULL, the MFC print architecture defaults to the system's default printer the first time a print operation is performed. The system default printer's DEVMODE and DEVNAMES are then copied to the MFC application's m_hDevMode and m_hDevNames data members.

Occasionally, a programmer may want to print to a printer other than the default printer without having the user specify it through the print dialog box. Two common examples are:

  • Set the default printer of the application to something other than the system's default printer.

-or-
  • Printing directly to a non-default printer such as another network printer.

Whether you need to use the non-default printer on a permanent basis or for only one print job, you need the DEVMODE and DEVNAMES structure to create the printer DC. The PRINTER_INFO_2 structure from GetPrinter() contains all the information needed to fill the DEVMODE and DEVNAMES structures. The printer DC can then be created by the programmer explicitly through CPrintDialog::CreatePrinterDC() or CDC::CreateDC() (among others), or implicitly through the MFC framework.

The sample code below shows how to use GetPrinter() to set the default printer of the application. The code implements a CMyApp function that uses the printer name supplied to globally allocate a new DEVMODE and DEVNAMES structures and set them to the data members of CWinApp. You can call this function from CMyApp::InitInstance(), or anywhere before printing. Note that these structures are not freed because the MFC framework handles this automatically.

To print directly to a non-default printer, create the structures in the OnPreparePrinting, set them to pInfo->m_pPD->m_pd's corresponding data members, and call pInfo-m_pPD->CreatePrinterDC(). Do not call DoPreparePrinting().

Sample Code

   class CMyApp : public CWinApp
   {
   public:
       CTestprintApp();
       BOOL SetPrinterDevice(char*);
       ...
   };

   #include <winspool.h>

   BOOL CMyApp::SetPrinterDevice(char* pszDeviceName)
   {
   // Open printer and obtain PRINTER_INFO_2 structure.
   HANDLE hPrinter;
   if (OpenPrinter(pszDeviceName, &hPrinter, NULL) == FALSE)
       return FALSE;
   DWORD dwBytesReturned, dwBytesNeeded;
   GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded);
   PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)GlobalAlloc(GPTR,
       dwBytesNeeded);
   if (GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded,
       &dwBytesReturned) == 0) {
   GlobalFree(p2);
   ClosePrinter(hPrinter);
   return FALSE;
   }
   ClosePrinter(hPrinter);

   // Allocate a global handle for DEVMODE and copy DEVMODE data.
   HGLOBAL  hDevMode = GlobalAlloc(GHND, sizeof(*p2->pDevMode));
   DEVMODE* pDevMode = (DEVMODE*)GlobalLock(hDevMode);
   memcpy(pDevMode, p2->pDevMode, sizeof(*p2->pDevMode));
   GlobalUnlock(hDevMode);

   // Compute size of DEVNAMES structure you'll need.
   DWORD drvNameLen = strlen(p2->pDriverName);  // driver name
   DWORD ptrNameLen = strlen(p2->pPrinterName); // printer name
   DWORD porNameLen = strlen(p2->pPortName);    // port name
   DWORD devNameSize = sizeof(DEVNAMES) +
       ptrNameLen + porNameLen + drvNameLen + 3;

   // Allocate a global handle big enough to hold DEVNAMES.
   HGLOBAL   hDevNames = GlobalAlloc(GHND, devNameSize);
   DEVNAMES* pDevNames = (DEVNAMES*)GlobalLock(hDevNames);

   // Copy the DEVNAMES information from PRINTER_INFO_2 structure.
   pDevNames->wDriverOffset = sizeof(DEVNAMES);
   memcpy((char*)pDevNames + pDevNames->wDriverOffset,
       p2->pDriverName, drvNameLen);

   pDevNames->wDeviceOffset = sizeof(DEVNAMES) +
   drvNameLen + 1;
   memcpy((char*)pDevNames + pDevNames->wDeviceOffset,
       p2->pPrinterName, ptrNameLen);

   pDevNames->wOutputOffset = sizeof(DEVNAMES) +
       drvNameLen + ptrNameLen + 2;
   memcpy((char*)pDevNames + pDevNames->wOutputOffset,
       p2->pPortName, porNameLen);

   pDevNames->wDefault = 0;

   GlobalUnlock(hDevNames);
   GlobalFree(p2);   // free PRINTER_INFO_2

   m_hDevMode = hDevMode;
   m_hDevNames = hDevNames;
   return TRUE;
   }

(c) Microsoft Corporation 1997, All Rights Reserved. Contributions by Adam Kim, Microsoft Corporation
Keywords          : MfcPrinting kbprint
Technology        : kbMfc
Version           : 4.0 4.1 4.2 4.2b 5.0
Platform          : NT WINDOWS
Issue type        : kbhowto


================================================================================


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: November 24, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.