Article ID: 112641
Article Last Modified on 3/7/2005
101413 Diagnosing Printing Problems in Your Application
119591 How to Obtain Microsoft Support Files from Online Services
#include <print.h> // Formerly DRIVINIT.H in 3.0
HINSTANCE hDriver; // Handle to driver
LPFNDEVMODE ExtDeviceMode; // Function pointer variable
PDEVMODE pdm; // Pointer to DEVMODE struct
int nSize; // Size of printer's DEVMODE struct
hDriver = LoadLibrary(szDriver);
if (hDriver < HINSTANCE_ERROR)
return; // Error
ExtDeviceMode = (LPFNDEVMODE) GetProcAddress(hDriver, "EXTDEVICEMODE");
if (!ExtDeviceMode)
{
FreeLibrary(hDriver); // ExtDeviceMode() not supported
return;
}
// Get size of DEVMODE
nSize = ExtDeviceMode(hWnd, hDriver, NULL, szDevice, szPort,
NULL, NULL, 0);
// Allocate buffer for DEVMODE
pdm = (PDEVMODE) LocalAlloc(LPTR, nSize); // check for failure!
Often, it is desirable to query the driver for the current printer
settings. This can be accomplished by allocating a buffer for the DEVMODE structure as above, and then calling ExtDeviceMode() a second time, passing the address of the output buffer and using the DM_OUT_BUFFER flag (also known as DM_COPY). For example:
ExtDeviceMode(hWnd, hDriver, pdm, szDevice, szPort, NULL, NULL, DM_COPY);Once the current settings are obtained, applications should use the dmFields member of the DEVMODE structure to determine which of the subsequent DEVMODE fields were initialized by the driver. Only fields with the corresponding bit set in dmFields should be used by the application; other fields are not supported by the driver.
DWORD dwFields;
...
dwFields = pdm->dmFields; // Save this
pdm->dmFields = 0 // We haven't changed anything yet
if (dwFields & DM_ORIENTATION)
{
pdm->dmFields |= DM_ORIENTATION;
pdm->dmOrientation = DMORIENT_LANDSCAPE;
}
// Continue changing other settings
A driver may support modifying a certain DEVMODE field without supporting all of the available settings for that field. For example, an application cannot use ExtDeviceMode() to switch to Executive paper if the printer only supports Letter, Legal, and A4 paper sizes. Applications should use DeviceCapabilities() to query the driver for this type of information.
For an example of using DeviceCapabilities(), please see the following article in the Microsoft Knowledge Base:
81245 DeviceCapabilities() Function Sample Code
ExtDeviceMode(hWnd, hDriver, pdm, szDevice, szPort,
pdm, NULL, DM_IN_BUFFER|DM_OUT_BUFFER);
DEVMODE is now ready for use in CreateDC() or ResetDC() for printing.
#include <windows.h>
#include <print.h> // Formerly DRIVINIT.H in 3.0
/**************************************************************************
**
FUNCTION: GetPrinterDC()
PURPOSE: Get hDC for default device according to information in the
"device" entry in the "windows" section of WIN.INI. Set
the device context to landscape orientation if supported.
COMMENTS: Calls ExtDeviceMode() in printer driver to set the device
context to landscape if supported.
See the documentation for ExtDeviceMode() and the DEVMODE
structure for more information.
RETURNS: hDC > 0 if success
hDC = 0 if failure
***************************************************************************
*/
HANDLE GetPrinterDC()
{
char pPrintInfo[80];
LPSTR lpTemp;
LPSTR lpPrintType;
LPSTR lpPrintDriver;
LPSTR lpPrintPort;
char pmodule[32];
HANDLE hDriver = 0;
HANDLE hDevMode = 0;
LPDEVMODE lpDevMode = NULL;
LPFNDEVMODE lpfnExtDeviceMode;
HDC hDC;
int count;
// Get the default printer information from WIN.ini.
// The string contains the printer name, driver filename, and port.
if (!GetProfileString("windows", "Device", (LPSTR)"", pPrintInfo, 80))
return (NULL);
// Parse the string we just got from WIN.INI.
// lpPrintDriver will be the driver filename (for example, HPPCL5MS).
// lpPrintType will be the printer name (for example, HP Laserjet III).
// lpPrintPort will be the port (for example, LPT1:).
lpTemp = lpPrintType = pPrintInfo;
lpPrintDriver = lpPrintPort = 0;
while (*lpTemp)
{
if (*lpTemp == ',')
{
*lpTemp++ = 0;
while (*lpTemp == ' ')
lpTemp = AnsiNext(lpTemp);
if (!lpPrintDriver)
lpPrintDriver = lpTemp;
else
{
lpPrintPort = lpTemp;
break;
}
}
else
lpTemp = AnsiNext(lpTemp);
}
// Build driver name
wsprintf (pmodule, "%s.drv",(LPSTR)lpPrintDriver);
// Load driver
if ((hDriver = LoadLibrary(pmodule)) > 31)
{
// Get a function pointer to the ExtDeviceMode() function.
// ExtDeviceMode() resides in the driver so we can't call it
// directly.
if (lpfnExtDeviceMode = (LPFNDEVMODE)GetProcAddress(hDriver,
(LPSTR)"EXTDEVICEMODE"))
{
// Get the number of bytes in the full DEVMODE buffer.
// This includes the device-dependent part at the end
// of the DEVMODE struct.
count = lpfnExtDeviceMode(0,
hDriver,
NULL,
lpPrintType,
lpPrintPort,
NULL,
NULL,
0); // 0 = get buffer size
if (count != -1)
{
// Allocate storage for the DEVMODE buffer.
hDevMode = GlobalAlloc(GHND, count);
if (hDevMode)
{
lpDevMode = (LPDEVMODE)GlobalLock(hDevMode);
// Get the current printer settings.
count = lpfnExtDeviceMode(0,
hDriver,
lpDevMode, // Output buffer
lpPrintType,
lpPrintPort,
NULL,
NULL,
DM_OUT_BUFFER); // aka DM_COPY
// Check to see if this printer supports changing
// the orientation. You should check dmFields
// before changing any printer setting.
if (lpDevMode->dmFields & DM_ORIENTATION)
{
// Pass lpDevMode as both the input and output
// DEVMODE buffers. It is important to pass
// in the full DEVMODE from the previous call
// to ExtDeviceMode() as the input buffer because
// it has been completely initialized by the
// driver. If you do not do this, the results
// are sporadic--sometimes it works and sometimes
// it doesn't depending on the printer driver and
// the setting you are trying to change.
// Zero out all the fields and then set the bit(s)
// for the field(s) we want to change.
lpDevMode->dmFields = 0;
lpDevMode->dmFields = DM_ORIENTATION;
// Change to landscape.
lpDevMode->dmOrientation = DMORIENT_LANDSCAPE;
// Call ExtDeviceMode() once more to allow the driver
// to change the device-dependent portion of the
// DEVMODE buffer if it needs to.
count = lpfnExtDeviceMode(0,
hDriver,
lpDevMode, //Output buffer
lpPrintType,
lpPrintPort,
lpDevMode, // Input buffer
NULL,
DM_OUT_BUFFER | DM_IN_BUFFER);
// aka DM_COPY | DM_MODIFY
hDC = CreateDC(lpPrintDriver,
lpPrintType,
lpPrintPort,
(void FAR*)lpDevMode);
}
else
{
// The printer doesn't support the field you're
// trying to change. Just use the current printer
// settings.
hDC = CreateDC(lpPrintDriver,
lpPrintType,
lpPrintPort,
(void FAR*)lpDevMode);
}
GlobalUnlock(hDevMode);
GlobalFree(hDevMode);
FreeLibrary(hDriver);
return hDC;
} // end hDevMode
} // end count != -1
} // end lpfnExtDeviceMode != 0
} // end hDriver > 31
// If we got here, an error has occurred so finish cleanup and return NULL.
if (hDriver)
FreeLibrary(hDriver);
return NULL;
} // end GetPrinterDC
There are some common variations to the above method when calling
ExtDeviceMode(). For example, if you just want to create a printer HDC using the current printer settings, you only need to call ExtDeviceMode() twice, as described above. The first call is to get the size of the full DEVMODE and the second call is to get the current printer settings. You then just pass the initialized LPDEVMODE to CreateDC.
Additional query words: EXTDEV print gpf gp-fault softlib kbfile
Keywords: kbinfo kbdownload kb16bitonly kbfile kbsample KB112641