/*++ Copyright (c) 1990-1993 Microsoft Corporation Module Name: devmode.c Abstract: This module contains devmode conversion Author: 08-Jun-1995 Thu 13:47:33 created -by- Daniel Chou (danielc) [Environment:] GDI printer drivers, user and kernel mode [Notes:] Revision History: 11/09/95 -davidx- New conversion routines --*/ #include #include #include #include // // This is the devmode version 320 (DM_SPECVERSION) // #define DM_SPECVERSION320 0x0320 #define DM_SPECVERSION400 0x0400 #define DM_SPECVERSION401 0x0401 #define DM_SPECVER_BASE DM_SPECVERSION320 // // size of a device name string // #define CCHDEVICENAME320 32 #define CCHFORMNAME320 32 typedef struct _devicemode320A { BYTE dmDeviceName[CCHDEVICENAME320]; WORD dmSpecVersion; WORD dmDriverVersion; WORD dmSize; WORD dmDriverExtra; DWORD dmFields; short dmOrientation; short dmPaperSize; short dmPaperLength; short dmPaperWidth; short dmScale; short dmCopies; short dmDefaultSource; short dmPrintQuality; short dmColor; short dmDuplex; short dmYResolution; short dmTTOption; short dmCollate; BYTE dmFormName[CCHFORMNAME320]; WORD dmLogPixels; DWORD dmBitsPerPel; DWORD dmPelsWidth; DWORD dmPelsHeight; DWORD dmDisplayFlags; DWORD dmDisplayFrequency; } DEVMODE320A, *PDEVMODE320A, *NPDEVMODE320A, *LPDEVMODE320A; typedef struct _devicemode320W { WCHAR dmDeviceName[CCHDEVICENAME320]; WORD dmSpecVersion; WORD dmDriverVersion; WORD dmSize; WORD dmDriverExtra; DWORD dmFields; short dmOrientation; short dmPaperSize; short dmPaperLength; short dmPaperWidth; short dmScale; short dmCopies; short dmDefaultSource; short dmPrintQuality; short dmColor; short dmDuplex; short dmYResolution; short dmTTOption; short dmCollate; WCHAR dmFormName[CCHFORMNAME320]; WORD dmLogPixels; DWORD dmBitsPerPel; DWORD dmPelsWidth; DWORD dmPelsHeight; DWORD dmDisplayFlags; DWORD dmDisplayFrequency; } DEVMODE320W, *PDEVMODE320W, *NPDEVMODE320W, *LPDEVMODE320W; #ifdef UNICODE typedef DEVMODE320W DEVMODE320; typedef PDEVMODE320W PDEVMODE320; typedef NPDEVMODE320W NPDEVMODE320; typedef LPDEVMODE320W LPDEVMODE320; #else typedef DEVMODE320A DEVMODE320; typedef PDEVMODE320A PDEVMODE320; typedef NPDEVMODE320A NPDEVMODE320; typedef LPDEVMODE320A LPDEVMODE320; #endif // UNICODE typedef struct _DMEXTRA400 { DWORD dmICMMethod; DWORD dmICMIntent; DWORD dmMediaType; DWORD dmDitherType; DWORD dmICCManufacturer; DWORD dmICCModel; } DMEXTRA400; typedef struct _DMEXTRA401 { DWORD dmPanningWidth; DWORD dmPanningHeight; } DMEXTRA401; #define DM_SIZE320 sizeof(DEVMODE320) #define DM_SIZE400 (DM_SIZE320 + sizeof(DMEXTRA400)) #define DM_SIZE401 (DM_SIZE400 + sizeof(DMEXTRA401)) // Current version devmode size - public portion only #ifdef UNICODE #define DM_SIZE_CURRENT sizeof(DEVMODEW) #else #define DM_SIZE_CURRENT sizeof(DEVMODEA) #endif WORD CheckDevmodeVersion( PDEVMODE pdm ) /*++ Routine Description: Verify dmSpecVersion and dmSize fields of a devmode Arguments: pdm - Specifies a devmode to be version-checked Return Value: 0 if the input devmode is unacceptable Otherwise, return the expected dmSpecVersion value --*/ { WORD expectedVersion; if (pdm == NULL) return 0; // Check against known devmode sizes switch (pdm->dmSize) { case DM_SIZE320: expectedVersion = DM_SPECVERSION320; break; case DM_SIZE400: expectedVersion = DM_SPECVERSION400; break; case DM_SIZE401: expectedVersion = DM_SPECVERSION401; break; default: expectedVersion = pdm->dmSpecVersion; break; } return expectedVersion; } LONG ConvertDevmode( PDEVMODE pdmIn, PDEVMODE pdmOut ) /*++ Routine Description: Convert an input devmode to a different version devmode. Whenever driver gets an input devmode, it should call this routine to convert it to current version. Arguments: pdmIn - Points to an input devmode pdmOut - Points to an initialized/valid output devmode Return Value: Total number of bytes copied -1 if either input or output devmode is invalid --*/ { WORD dmSpecVersion, dmDriverVersion; WORD dmSize, dmDriverExtra; LONG cbCopied = 0; // Look for inconsistency between dmSpecVersion and dmSize if (! CheckDevmodeVersion(pdmIn) || ! (dmSpecVersion = CheckDevmodeVersion(pdmOut))) { return -1; } // Copy public devmode fields dmDriverVersion = pdmOut->dmDriverVersion; dmSize = pdmOut->dmSize; dmDriverExtra = pdmOut->dmDriverExtra; cbCopied = min(dmSize, pdmIn->dmSize); memcpy(pdmOut, pdmIn, cbCopied); pdmOut->dmSpecVersion = dmSpecVersion; pdmOut->dmDriverVersion = dmDriverVersion; pdmOut->dmSize = dmSize; pdmOut->dmDriverExtra = dmDriverExtra; // Copy private devmode fields cbCopied += min(dmDriverExtra, pdmIn->dmDriverExtra); memcpy((PBYTE) pdmOut + pdmOut->dmSize, (PBYTE) pdmIn + pdmIn->dmSize, min(dmDriverExtra, pdmIn->dmDriverExtra)); return cbCopied; } #ifndef KERNEL_MODE #include #include #include #include BOOL ConvertDevmodeOut( PDEVMODE pdmSrc, PDEVMODE pdmIn, PDEVMODE pdmOut ) /*++ Routine Description: Copy a source devmode to an output devmode buffer. Driver should call this routine before it returns to the caller of DrvDocumentProperties. Arguments: pdmSrc - Points to a current version source devmode pdmIn - Points to input devmode passed to DrvDocumentProperties pdmOut - Output buffer pointer passed to DrvDocumentProperties Return Value: TRUE if successful, FALSE otherwise --*/ { if (pdmIn == NULL) { memcpy(pdmOut, pdmSrc, pdmSrc->dmSize + pdmSrc->dmDriverExtra); return TRUE; } else { // We have to deal with the public fields and private fields // separately. Also remember pdmIn and pdmOut may point to // the same buffer. // Public fields: take dmSpecVersion and dmSize from // the smaller of pdmSrc and pdmIn if (pdmIn->dmSize < pdmSrc->dmSize) { pdmOut->dmSpecVersion = pdmIn->dmSpecVersion; pdmOut->dmSize = pdmIn->dmSize; } else { pdmOut->dmSpecVersion = pdmSrc->dmSpecVersion; pdmOut->dmSize = pdmSrc->dmSize; } // Similarly for private fields if (pdmIn->dmDriverExtra < pdmSrc->dmDriverExtra) { pdmOut->dmDriverVersion = pdmIn->dmDriverVersion; pdmOut->dmDriverExtra = pdmIn->dmDriverExtra; } else { pdmOut->dmDriverVersion = pdmSrc->dmDriverVersion; pdmOut->dmDriverExtra = pdmSrc->dmDriverExtra; } return ConvertDevmode(pdmSrc, pdmOut) > 0; } } INT CommonDrvConvertDevmode( PWSTR pPrinterName, PDEVMODE pdmIn, PDEVMODE pdmOut, PLONG pcbNeeded, DWORD fMode, PDRIVER_VERSION_INFO pDriverVersions ) /*++ Routine Description: Library routine to handle common cases of DrvConvertDevMode Arguments: pPrinterName, pdmIn, pdmOut, pcbNeeded, fMode Correspond to parameters passed to DrvConvertDevMode pDriverVersions - Specifies driver version numbers and private devmode sizes Return Value: CDM_RESULT_TRUE If the case is handled by the library routine and driver shoud return TRUE to the caller of DrvConvertDevMode. CDM_RESULT_FALSE If the case is handled by the library routine and driver shoud return FALSE to the caller of DrvConvertDevMode. CDM_RESULT_NOT_HANDLED The case is NOT handled by the library routine and driver should continue on with whatever it needs to do. --*/ { LONG size; // Make sure pcbNeeded parameter is not NULL if (pcbNeeded == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return CDM_RESULT_FALSE; } switch (fMode) { case CDM_CONVERT: // Convert any input devmode to any output devmode. // Both input and output must be valid. if (pdmOut != NULL && *pcbNeeded >= (pdmOut->dmSize + pdmOut->dmDriverExtra) && ConvertDevmode(pdmIn, pdmOut) > 0) { *pcbNeeded = pdmOut->dmSize + pdmOut->dmDriverExtra; return CDM_RESULT_TRUE; } break; case CDM_CONVERT351: // Convert any input devmode to 3.51 version devmode // First check if the caller provided buffer is large enough size = DM_SIZE320 + pDriverVersions->dmDriverExtra351; if (*pcbNeeded < size || pdmOut == NULL) { *pcbNeeded = size; SetLastError(ERROR_INSUFFICIENT_BUFFER); return CDM_RESULT_FALSE; } // Do the conversion from input devmode to 3.51 devmode pdmOut->dmSpecVersion = DM_SPECVERSION320; pdmOut->dmSize = DM_SIZE320; pdmOut->dmDriverVersion = pDriverVersions->dmDriverVersion351; pdmOut->dmDriverExtra = pDriverVersions->dmDriverExtra351; if (ConvertDevmode(pdmIn, pdmOut) > 0) { *pcbNeeded = size; return CDM_RESULT_TRUE; } break; case CDM_DRIVER_DEFAULT: // Convert any input devmode to current version devmode // First check if the caller provided buffer is large enough size = DM_SIZE_CURRENT + pDriverVersions->dmDriverExtra; if (*pcbNeeded < size || pdmOut == NULL) { *pcbNeeded = size; SetLastError(ERROR_INSUFFICIENT_BUFFER); return CDM_RESULT_FALSE; } // This case (getting driver-default devmode) is not handled // by the library routine. *pcbNeeded = size; // FALL THROUGH TO THE DEFAULT CASE! default: return CDM_RESULT_NOT_HANDLED; } SetLastError(ERROR_INVALID_PARAMETER); return CDM_RESULT_FALSE; } #endif // !KERNEL_MODE