/*++ Copyright (c) 1996-1997 Microsoft Corporation Module Name: psutil.c Abstract: PostScript utility functions BInitDriverDefaultDevmode BMergeDriverDevmode VCopyUnicodeStringToAnsi PGetAndConvertOldVersionFormTrayTable BSaveAsOldVersionFormTrayTable Environment: Windows NT printer drivers Revision History: 12/03/97 -fengy- Added VUpdatePrivatePrinterData to split fixed fields in PrinterData into Keyword/Value pairs in Registry. 04/17/97 -davidx- Provide OEM plugins access to driver private devmode settings. 02/04/97 -davidx- Devmode changes to support OEM plugins. 10/02/96 -davidx- Implement BPSMergeDevmode. 09/26/96 -davidx- Created it. --*/ #include "lib.h" #include "ppd.h" #include "pslib.h" #include "oemutil.h" // // Information about PostScript driver private devmode // CONST DRIVER_DEVMODE_INFO gDriverDMInfo = { PSDRIVER_VERSION, sizeof(PSDRVEXTRA), PSDRIVER_VERSION_500, sizeof(PSDRVEXTRA500), PSDRIVER_VERSION_400, sizeof(PSDRVEXTRA400), PSDRIVER_VERSION_351, sizeof(PSDRVEXTRA351), }; CONST DWORD gdwDriverDMSignature = PSDEVMODE_SIGNATURE; CONST WORD gwDriverVersion = PSDRIVER_VERSION; static VOID VInitNewPrivateFields( PRAWBINARYDATA pRawData, PUIINFO pUIInfo, PPSDRVEXTRA pdmPrivate, BOOL bInitAllFields ) /*++ Routine Description: Intialize the new private devmode fields for PS 5.0 Arguments: pUIInfo - Points to a UIINFO structure pRawData - Points to raw binary printer description data pdmPrivate - Points to the private devmode fields to be initialized bInitAllFields - Whether to initialize all new private fields or initialize the options array only Return Value: NONE --*/ { if (bInitAllFields) { pdmPrivate->wReserved1 = 0; pdmPrivate->wSize = sizeof(PSDRVEXTRA); pdmPrivate->fxScrFreq = 0; pdmPrivate->fxScrAngle = 0; pdmPrivate->iDialect = SPEED; pdmPrivate->iTTDLFmt = TT_DEFAULT; pdmPrivate->bReversePrint = FALSE; pdmPrivate->iLayout = ONE_UP; pdmPrivate->iPSLevel = pUIInfo->dwLangLevel; pdmPrivate->wOEMExtra = 0; pdmPrivate->wVer = PSDRVEXTRA_VERSION; pdmPrivate->dwReserved2 = 0; ZeroMemory(pdmPrivate->dwReserved3, sizeof(pdmPrivate->dwReserved3)); } InitDefaultOptions(pRawData, pdmPrivate->aOptions, MAX_PRINTER_OPTIONS, MODE_DOCUMENT_STICKY); pdmPrivate->dwOptions = pRawData->dwDocumentFeatures; pdmPrivate->dwChecksum32 = pRawData->dwChecksum32; } BOOL BInitDriverDefaultDevmode( OUT PDEVMODE pdmOut, IN LPCTSTR ptstrPrinterName, IN PUIINFO pUIInfo, IN PRAWBINARYDATA pRawData, IN BOOL bMetric ) /*++ Routine Description: Return the driver default devmode Arguments: pdmOut - Points to the output devmode to be initialized ptstrPrinterName - Specifies the name of the printer pUIInfo - Points to a UIINFO structure pRawData - Points to raw binary printer description data bMetric - Whether the system is running in metric mode Return Value: TRUE if successful, FALSE if there is an error Note: This function should initialize both public devmode fields and driver private devmode fields. It's also assumed that output buffer has already been zero initialized by the caller. --*/ { PPSDRVEXTRA pdmPrivate; PFEATURE pFeature; PPPDDATA pPpdData; // // Initialize public devmode fields // pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData); ASSERT(pPpdData != NULL); pdmOut->dmDriverVersion = PSDRIVER_VERSION; pdmOut->dmSpecVersion = DM_SPECVERSION; pdmOut->dmSize = sizeof(DEVMODE); pdmOut->dmDriverExtra = sizeof(PSDRVEXTRA); pdmOut->dmFields = DM_ORIENTATION | DM_SCALE | DM_COPIES | DM_PRINTQUALITY | DM_YRESOLUTION | DM_TTOPTION | #ifndef WINNT_40 DM_NUP | #endif DM_COLOR | DM_DEFAULTSOURCE; pdmOut->dmOrientation = DMORIENT_PORTRAIT; pdmOut->dmDuplex = DMDUP_SIMPLEX; pdmOut->dmCollate = DMCOLLATE_FALSE; pdmOut->dmMediaType = DMMEDIA_STANDARD; pdmOut->dmTTOption = DMTT_SUBDEV; pdmOut->dmColor = DMCOLOR_MONOCHROME; pdmOut->dmDefaultSource = DMBIN_FORMSOURCE; pdmOut->dmScale = 100; pdmOut->dmCopies = 1; pdmOut->dmPrintQuality = pdmOut->dmYResolution = DEFAULT_RESOLUTION; #ifndef WINNT_40 pdmOut->dmNup = DMNUP_SYSTEM; #endif if (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_RESOLUTION)) { PRESOLUTION pRes; // // Use the default resolution specified in the PPD file // if (pRes = PGetIndexedOption(pUIInfo, pFeature, pFeature->dwDefaultOptIndex)) { pdmOut->dmPrintQuality = (short)pRes->iXdpi; pdmOut->dmYResolution = (short)pRes->iYdpi; } } if (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_DUPLEX)) { PDUPLEX pDuplex; // // Use the default duplex option specified in the PPD file // pdmOut->dmFields |= DM_DUPLEX; if (pDuplex = PGetIndexedOption(pUIInfo, pFeature, pFeature->dwDefaultOptIndex)) pdmOut->dmDuplex = (SHORT) pDuplex->dwDuplexID; } #ifdef WINNT_40 if (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_COLLATE)) { PCOLLATE pCollate; pdmOut->dmFields |= DM_COLLATE; if (pCollate = PGetIndexedOption(pUIInfo, pFeature, pFeature->dwDefaultOptIndex)) pdmOut->dmCollate = (SHORT) pCollate->dwCollateID; } #else // !WINNT_40 pdmOut->dmFields |= DM_COLLATE; pdmOut->dmCollate = DMCOLLATE_TRUE; #endif // !WINNT_40 if (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_MEDIATYPE)) { // // Use the default media type specified in the PPD file // pdmOut->dmFields |= DM_MEDIATYPE; if (pFeature->dwDefaultOptIndex != OPTION_INDEX_ANY) pdmOut->dmMediaType = DMMEDIA_USER + pFeature->dwDefaultOptIndex; } // // Adobe wants to preserve the color information even for b/w printers. // So for both b/w and color printers, turn color on by default for Adobe. // #ifndef ADOBE if (IS_COLOR_DEVICE(pUIInfo)) { #endif // !ADOBE // // Turn color on by default // pdmOut->dmColor = DMCOLOR_COLOR; pdmOut->dmFields |= DM_COLOR; #ifndef ADOBE } #endif // !ADOBE // // We always set ICM off. The spooler will turn it on at install time // if there are color profiles installed with this printer // pdmOut->dmICMMethod = DMICMMETHOD_NONE; pdmOut->dmICMIntent = DMICM_CONTRAST; #ifndef WINNT_40 #ifndef ADOBE if (IS_COLOR_DEVICE(pUIInfo)) { #endif // !ADOBE pdmOut->dmFields |= (DM_ICMMETHOD | DM_ICMINTENT); #ifndef ADOBE } #endif // !ADOBE #endif // !WINNT_40 // // dmDeviceName field will be filled elsewhere. // Use an arbitrary default value if the input parameter is NULL. // CopyString(pdmOut->dmDeviceName, ptstrPrinterName ? ptstrPrinterName : TEXT("PostScript"), CCHDEVICENAME); // // Initialize form-related fields // VDefaultDevmodeFormFields(pUIInfo, pdmOut, bMetric); // // Private devmode fields // pdmPrivate = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdmOut); pdmPrivate->dwSignature = PSDEVMODE_SIGNATURE; pdmPrivate->coloradj = gDefaultHTColorAdjustment; #ifndef WINNT_40 pdmPrivate->dwFlags = PSDEVMODE_METAFILE_SPOOL; #endif if (pPpdData->dwFlags & PPDFLAG_PRINTPSERROR) pdmPrivate->dwFlags |= PSDEVMODE_EHANDLER; if (pUIInfo->dwLangLevel > 1) pdmPrivate->dwFlags |= PSDEVMODE_COMPRESSBMP; #ifndef KERNEL_MODE // // Set up some private devmode flag bits for compatibility // with previous versions of the driver. // pdmPrivate->dwFlags |= PSDEVMODE_CTRLD_AFTER; if (GetACP() == 1252) pdmPrivate->dwFlags |= (PSDEVMODE_FONTSUBST|PSDEVMODE_ENUMPRINTERFONTS); #endif // // Intialize the new private devmode fields for PS 5.0 // VInitNewPrivateFields(pRawData, pUIInfo, pdmPrivate, TRUE); if (SUPPORT_CUSTOMSIZE(pUIInfo)) { VFillDefaultCustomPageSizeData(pRawData, &pdmPrivate->csdata, bMetric); } else { ZeroMemory(&pdmPrivate->csdata, sizeof(pdmPrivate->csdata)); pdmPrivate->csdata.dwX = pdmOut->dmPaperWidth * DEVMODE_PAPER_UNIT; pdmPrivate->csdata.dwY = pdmOut->dmPaperLength * DEVMODE_PAPER_UNIT; } return TRUE; } BOOL BMergeDriverDevmode( IN OUT PDEVMODE pdmOut, IN PUIINFO pUIInfo, IN PRAWBINARYDATA pRawData, IN PDEVMODE pdmIn ) /*++ Routine Description: Merge the input devmode with an existing devmode. Arguments: pdmOut - Points to a valid output devmode pUIInfo - Points to a UIINFO structure pRawData - Points to raw binary printer description data pdmIn - Points to the input devmode Return Value: TRUE if successful, FALSE if there is a fatal error Note: This function should take care of both public devmode fields and driver private devmode fields. It can assume the input devmode has already been convert to the current size. --*/ { PPSDRVEXTRA pdmPrivateIn, pdmPrivateOut; PFEATURE pFeature; PPPDDATA pPpdData; ASSERT(pdmOut != NULL && pdmOut->dmSize == sizeof(DEVMODE) && pdmOut->dmDriverExtra >= sizeof(PSDRVEXTRA) && pdmIn != NULL && pdmIn->dmSize == sizeof(DEVMODE) && pdmIn->dmDriverExtra >= sizeof(PSDRVEXTRA)); pdmPrivateIn = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdmIn); pdmPrivateOut = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdmOut); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData); ASSERT(pPpdData != NULL); // // Merge the public devmode fields // #ifndef WINNT_40 if ( (pdmIn->dmFields & DM_NUP) && (pdmIn->dmNup == DMNUP_SYSTEM || pdmIn->dmNup == DMNUP_ONEUP)) { pdmOut->dmNup = pdmIn->dmNup; pdmOut->dmFields |= DM_NUP; } #endif // #ifndef WINNT_40 if (pdmIn->dmFields & DM_DEFAULTSOURCE && ((pdmIn->dmDefaultSource >= DMBIN_FIRST && pdmIn->dmDefaultSource <= DMBIN_LAST) || pdmIn->dmDefaultSource >= DMBIN_USER)) { pdmOut->dmFields |= DM_DEFAULTSOURCE; pdmOut->dmDefaultSource = pdmIn->dmDefaultSource; } if ((pdmIn->dmFields & DM_ORIENTATION) && (pdmIn->dmOrientation == DMORIENT_PORTRAIT || pdmIn->dmOrientation == DMORIENT_LANDSCAPE)) { pdmOut->dmFields |= DM_ORIENTATION; pdmOut->dmOrientation = pdmIn->dmOrientation; } // // If both DM_PAPERLENGTH and DM_PAPERWIDTH are set, copy // dmPaperLength and dmPaperWidth fields. If DM_PAPERSIZE // is set, copy dmPaperSize field. Otherwise, if DM_FORMNAME // is set, copy dmFormName field. // if ((pdmIn->dmFields & DM_PAPERWIDTH) && (pdmIn->dmFields & DM_PAPERLENGTH) && (pdmIn->dmPaperWidth > 0) && (pdmIn->dmPaperLength > 0)) { pdmOut->dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH); pdmOut->dmFields &= ~(DM_PAPERSIZE | DM_FORMNAME); pdmOut->dmPaperWidth = pdmIn->dmPaperWidth; pdmOut->dmPaperLength = pdmIn->dmPaperLength; } else if (pdmIn->dmFields & DM_PAPERSIZE) { if ((pdmIn->dmPaperSize != DMPAPER_CUSTOMSIZE) || SUPPORT_CUSTOMSIZE(pUIInfo) && SUPPORT_FULL_CUSTOMSIZE_FEATURES(pUIInfo, pPpdData)) { pdmOut->dmFields |= DM_PAPERSIZE; pdmOut->dmFields &= ~(DM_PAPERLENGTH | DM_PAPERWIDTH | DM_FORMNAME); pdmOut->dmPaperSize = pdmIn->dmPaperSize; } } else if (pdmIn->dmFields & DM_FORMNAME) { pdmOut->dmFields |= DM_FORMNAME; pdmOut->dmFields &= ~(DM_PAPERLENGTH | DM_PAPERWIDTH | DM_PAPERSIZE); CopyString(pdmOut->dmFormName, pdmIn->dmFormName, CCHFORMNAME); } if ((pdmIn->dmFields & DM_SCALE) && (pdmIn->dmScale >= MIN_SCALE) && (pdmIn->dmScale <= MAX_SCALE)) { pdmOut->dmFields |= DM_SCALE; pdmOut->dmScale = pdmIn->dmScale; } if ((pdmIn->dmFields & DM_COPIES) && (pdmIn->dmCopies >= 1) && (pdmIn->dmCopies <= (SHORT) pUIInfo->dwMaxCopies)) { pdmOut->dmFields |= DM_COPIES; pdmOut->dmCopies = pdmIn->dmCopies; } if ((pdmIn->dmFields & DM_DUPLEX) && (GET_PREDEFINED_FEATURE(pUIInfo, GID_DUPLEX) != NULL) && (pdmIn->dmDuplex == DMDUP_SIMPLEX || pdmIn->dmDuplex == DMDUP_HORIZONTAL || pdmIn->dmDuplex == DMDUP_VERTICAL)) { pdmOut->dmFields |= DM_DUPLEX; pdmOut->dmDuplex = pdmIn->dmDuplex; } if ((pdmIn->dmFields & DM_COLLATE) && #ifdef WINNT_40 GET_PREDEFINED_FEATURE(pUIInfo, GID_COLLATE) != NULL && #endif (pdmIn->dmCollate == DMCOLLATE_TRUE || pdmIn->dmCollate == DMCOLLATE_FALSE)) { pdmOut->dmFields |= DM_COLLATE; pdmOut->dmCollate = pdmIn->dmCollate; } if ((pdmIn->dmFields & DM_TTOPTION) && (pdmIn->dmTTOption == DMTT_BITMAP || pdmIn->dmTTOption == DMTT_DOWNLOAD || pdmIn->dmTTOption == DMTT_SUBDEV)) { pdmOut->dmFields |= DM_TTOPTION; pdmOut->dmTTOption = (pdmIn->dmTTOption == DMTT_SUBDEV) ? DMTT_SUBDEV : DMTT_DOWNLOAD; } // // Merge color and ICM fields. // #ifndef ADOBE if (IS_COLOR_DEVICE(pUIInfo)) { #endif // !ADOBE if ((pdmIn->dmFields & DM_COLOR) && (pdmIn->dmColor == DMCOLOR_COLOR || pdmIn->dmColor == DMCOLOR_MONOCHROME)) { pdmOut->dmFields |= DM_COLOR; pdmOut->dmColor = pdmIn->dmColor; } #ifndef WINNT_40 if ((pdmIn->dmFields & DM_ICMMETHOD) && (pdmIn->dmICMMethod == DMICMMETHOD_NONE || pdmIn->dmICMMethod == DMICMMETHOD_SYSTEM || pdmIn->dmICMMethod == DMICMMETHOD_DRIVER || pdmIn->dmICMMethod == DMICMMETHOD_DEVICE)) { pdmOut->dmFields |= DM_ICMMETHOD; pdmOut->dmICMMethod = pdmIn->dmICMMethod; } if ((pdmIn->dmFields & DM_ICMINTENT) && (pdmIn->dmICMIntent == DMICM_SATURATE || pdmIn->dmICMIntent == DMICM_CONTRAST || pdmIn->dmICMIntent == DMICM_COLORIMETRIC || pdmIn->dmICMIntent == DMICM_ABS_COLORIMETRIC)) { pdmOut->dmFields |= DM_ICMINTENT; pdmOut->dmICMIntent = pdmIn->dmICMIntent; } #endif // !WINNT_40 #ifndef ADOBE } #endif // !ADOBE // // Resolution // if ((pdmIn->dmFields & (DM_PRINTQUALITY|DM_YRESOLUTION)) && (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_RESOLUTION))) { PRESOLUTION pRes; DWORD dwIndex; INT iXdpi, iYdpi; switch (pdmIn->dmFields & (DM_PRINTQUALITY|DM_YRESOLUTION)) { case DM_PRINTQUALITY: iXdpi = iYdpi = pdmIn->dmPrintQuality; break; case DM_YRESOLUTION: iXdpi = iYdpi = pdmIn->dmYResolution; break; default: iXdpi = pdmIn->dmPrintQuality; iYdpi = pdmIn->dmYResolution; break; } dwIndex = MapToDeviceOptIndex(pUIInfo->pInfoHeader, GID_RESOLUTION, iXdpi, iYdpi, NULL); if (pRes = PGetIndexedOption(pUIInfo, pFeature, dwIndex)) { pdmOut->dmFields |= (DM_PRINTQUALITY|DM_YRESOLUTION); pdmOut->dmPrintQuality = (short)pRes->iXdpi; pdmOut->dmYResolution = (short)pRes->iYdpi; } } // // Media type // if ((pdmIn->dmFields & DM_MEDIATYPE) && (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_MEDIATYPE)) && (pdmIn->dmMediaType == DMMEDIA_STANDARD || pdmIn->dmMediaType == DMMEDIA_TRANSPARENCY || pdmIn->dmMediaType == DMMEDIA_GLOSSY || ((pdmIn->dmMediaType >= DMMEDIA_USER) && (pdmIn->dmMediaType < DMMEDIA_USER + pFeature->Options.dwCount)))) { pdmOut->dmFields |= DM_MEDIATYPE; pdmOut->dmMediaType = pdmIn->dmMediaType; } // // Merge the private devmode fields // if (pdmPrivateIn->dwSignature == PSDEVMODE_SIGNATURE) { CopyMemory(pdmPrivateOut, pdmPrivateIn, sizeof(PSDRVEXTRA)); if (pdmPrivateOut->dwChecksum32 != pRawData->dwChecksum32) { WARNING(("PSCRIPT5: Devmode checksum mismatch.\n")); // // Intialize the new private devmode fields for PS 5.0. // If wReserved1 field is not 0, then the devmode is of // a previous version. In that case, we should initialize // all new private fields instead of just the options array. // VInitNewPrivateFields(pRawData, pUIInfo, pdmPrivateOut, pdmPrivateOut->wReserved1 != 0); // // Convert PS4 feature/option selections to PS4 format // if (pdmPrivateIn->wReserved1 == pPpdData->dwNt4Checksum) { VConvertOptSelectArray(pRawData, pdmPrivateOut->aOptions, MAX_PRINTER_OPTIONS, ((PSDRVEXTRA400 *) pdmPrivateIn)->aubOptions, 64, MODE_DOCUMENT_STICKY); } } if (pdmPrivateOut->iPSLevel == 0 || pdmPrivateOut->iPSLevel > (INT) pUIInfo->dwLangLevel) { pdmPrivateOut->iPSLevel = pUIInfo->dwLangLevel; } if (pdmPrivateOut->iTTDLFmt == TYPE_42 && pUIInfo->dwTTRasterizer != TTRAS_TYPE42) pdmPrivateOut->iTTDLFmt = TT_DEFAULT; if (IS_COLOR_DEVICE(pUIInfo)) { pdmPrivateOut->dwFlags &= ~PSDEVMODE_NEG; } } // // If custom page size is supported, make sure the custom page // size parameters are valid. // if (SUPPORT_CUSTOMSIZE(pUIInfo)) (VOID) BValidateCustomPageSizeData(pRawData, &pdmPrivateOut->csdata); return TRUE; } BOOL BValidateDevmodeCustomPageSizeFields( PRAWBINARYDATA pRawData, PUIINFO pUIInfo, PDEVMODE pdm, PRECTL prclImageArea ) /*++ Routine Description: Check if the devmode form fields are specifying PostScript custom page size Arguments: pRawData - Points to raw printer description data pUIInfo - Points to UIINFO structure pdm - Points to input devmode prclImageArea - Returns imageable area of the custom page size Return Value: TRUE if the devmode specifies PostScript custom page size FALSE otherwise --*/ { PPPDDATA pPpdData; PPSDRVEXTRA pdmPrivate; pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData); ASSERT(pPpdData != NULL); if ((pdm->dmFields & DM_PAPERSIZE) && pdm->dmPaperSize == DMPAPER_CUSTOMSIZE && SUPPORT_CUSTOMSIZE(pUIInfo) && SUPPORT_FULL_CUSTOMSIZE_FEATURES(pUIInfo, pPpdData)) { pdmPrivate = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdm); pdm->dmFields &= ~(DM_PAPERWIDTH|DM_PAPERLENGTH|DM_FORMNAME); pdm->dmPaperWidth = (SHORT) (pdmPrivate->csdata.dwX / DEVMODE_PAPER_UNIT); pdm->dmPaperLength = (SHORT) (pdmPrivate->csdata.dwY / DEVMODE_PAPER_UNIT); ZeroMemory(pdm->dmFormName, sizeof(pdm->dmFormName)); if (prclImageArea) { prclImageArea->left = prclImageArea->top = 0; prclImageArea->right = pdmPrivate->csdata.dwX; prclImageArea->bottom = pdmPrivate->csdata.dwY; } return TRUE; } return FALSE; } VOID VCopyUnicodeStringToAnsi( PSTR pstr, PCWSTR pwstr, INT iMaxChars ) /*++ Routine Description: Convert an ANSI string to a UNICODE string (using the current ANSI codepage) Arguments: pstr - Pointer to buffer for holding ANSI string pwstr - Pointer to Unicode string iMaxChars - Maximum number of ANSI characters to copy Return Value: NONE Note: If iMaxChars is 0 or negative, we assume the caller has provided an ANSI buffer that's sufficiently large to do the conversion. --*/ { INT iLen = wcslen(pwstr) + 1; if (iMaxChars <= 0) iMaxChars = iLen; #ifdef KERNEL_MODE (VOID) EngUnicodeToMultiByteN(pstr, iMaxChars, NULL, (PWSTR) pwstr, iLen*sizeof(WCHAR)); #else // !KERNEL_MODE (VOID) WideCharToMultiByte(CP_ACP, 0, pwstr, iLen, pstr, iMaxChars, NULL, NULL); #endif pstr[iMaxChars - 1] = NUL; } FORM_TRAY_TABLE PGetAndConvertOldVersionFormTrayTable( IN HANDLE hPrinter, OUT PDWORD pdwSize ) /*++ Routine Description: Retrieve the old form-to-tray assignment table from registry and convert it to the new format for the caller. Arguments: hPrinter - Handle to the printer object pdwSize - Returns the form-to-tray assignment table size Return Value: Pointer to form-to-tray assignment table read from the registry NULL if there is an error --*/ { PTSTR ptstrNewTable; PTSTR ptstrOld, ptstrEnd, ptstrNew, ptstrSave; DWORD dwTableSize, dwNewTableSize; FORM_TRAY_TABLE pFormTrayTable; // // Retrieve the form-to-tray assignment information from registry // pFormTrayTable = PvGetPrinterDataBinary(hPrinter, REGVAL_TRAY_FORM_SIZE_PS40, REGVAL_TRAY_FORM_TABLE_PS40, &dwTableSize); if (pFormTrayTable == NULL) return NULL; // // Simple validation to make sure the information is valid // Old format contains the table size as the first field in table // if (dwTableSize != *pFormTrayTable) { ERR(("Corrupted form-to-tray assignment table!\n")); SetLastError(ERROR_INVALID_DATA); MemFree(pFormTrayTable); return NULL; } // // Convert the old format form-to-tray assignment table to new format // OLD NEW // Tray Name Tray Name // Form Name Form Name // Printer Form // IsDefaultTray // // // The first WCHAR hold the size of the table // dwTableSize -= sizeof(WCHAR); ptstrOld = pFormTrayTable + 1; ptstrEnd = ptstrOld + (dwTableSize / sizeof(WCHAR) - 1); // // Figuring out the size of new table, the last entry in the table // is always a NUL so add the count for it here first // dwNewTableSize = 1; while (ptstrOld < ptstrEnd && *ptstrOld != NUL) { ptstrSave = ptstrOld; ptstrOld += _tcslen(ptstrOld) + 1; ptstrOld += _tcslen(ptstrOld) + 1; // // New format contain only TrayName and FormName // dwNewTableSize += (DWORD)(ptstrOld - ptstrSave); // // Skip printer form and IsDefaultTray flag // ptstrOld += _tcslen(ptstrOld) + 2; } dwNewTableSize *= sizeof(WCHAR); if ((ptstrOld != ptstrEnd) || (*ptstrOld != NUL) || (ptstrNewTable = MemAlloc(dwNewTableSize)) == NULL) { ERR(( "Couldn't convert form-to-tray assignment table.\n")); MemFree(pFormTrayTable); return NULL; } // // The first WCHAR contains the table size // ptstrOld = pFormTrayTable + 1; ptstrNew = ptstrNewTable; while (*ptstrOld != NUL) { // // Copy slot name, form name // ptstrSave = ptstrOld; ptstrOld += _tcslen(ptstrOld) + 1; ptstrOld += _tcslen(ptstrOld) + 1; CopyMemory(ptstrNew, ptstrSave, (ptstrOld - ptstrSave) * sizeof(WCHAR)); ptstrNew += (ptstrOld - ptstrSave); // // skip printer form and IsDefaultTray flag // ptstrOld += _tcslen(ptstrOld) + 2; } // // The last WCHAR is a NUL-terminator // *ptstrNew = NUL; if (pdwSize) *pdwSize = dwNewTableSize; MemFree(pFormTrayTable); ASSERT(BVerifyMultiSZPair(ptstrNewTable, dwNewTableSize)); return(ptstrNewTable); } #ifndef KERNEL_MODE BOOL BSaveAsOldVersionFormTrayTable( IN HANDLE hPrinter, IN FORM_TRAY_TABLE pFormTrayTable, IN DWORD dwSize ) /*++ Routine Description: Save form-to-tray assignment table in NT 4.0 compatible format Arguments: hPrinter - Handle to the current printer pFormTrayTable - Points to new format form-tray table dwSize - Size of form-tray table to be saved, in bytes Return Value: TRUE if successful, FALSE if there is an error --*/ { DWORD dwOldTableSize; PTSTR ptstrNew, ptstrOld, ptstrOldTable; BOOL bResult; // // Find out how much memory to allocate for old format table // Old format table has size as its very first character // ASSERT((dwSize % sizeof(TCHAR)) == 0 && dwSize >= sizeof(TCHAR)); dwOldTableSize = dwSize + sizeof(WCHAR); ptstrNew = pFormTrayTable; while (*ptstrNew != NUL) { // // Skip tray name and form name // ptstrNew += _tcslen(ptstrNew) + 1; ptstrNew += _tcslen(ptstrNew) + 1; // // Old format has two extra characters per entry // one for the empty PrinterForm field // another for IsDefaultTray flag // dwOldTableSize += 2 * sizeof(TCHAR); } if ((ptstrOldTable = MemAlloc(dwOldTableSize)) == NULL) { ERR(("Memory allocation failed\n")); return FALSE; } // // Convert new format table to old format // Be careful about the IsDefaultTray flag // ptstrNew = pFormTrayTable; ptstrOld = ptstrOldTable; *ptstrOld++ = (TCHAR) dwOldTableSize; while (*ptstrNew != NUL) { // // Copy slot name and form name // FINDFORMTRAY FindData; DWORD dwCount; PTSTR ptstrTrayName, ptstrFormName; ptstrTrayName = ptstrNew; ptstrNew += _tcslen(ptstrNew) + 1; ptstrFormName = ptstrNew; ptstrNew += _tcslen(ptstrNew) + 1; CopyMemory(ptstrOld, ptstrTrayName, (ptstrNew - ptstrTrayName) * sizeof(TCHAR)); ptstrOld += (ptstrNew - ptstrTrayName); // // Set PrinterForm field to NUL // *ptstrOld++ = NUL; // // Set IsDefaultTray flag appropriately // dwCount = 0; RESET_FINDFORMTRAY(pFormTrayTable, &FindData); while (BSearchFormTrayTable(pFormTrayTable, NULL, ptstrFormName, &FindData)) dwCount++; *ptstrOld++ = (dwCount == 1) ? TRUE : FALSE; } // // The last character is a NUL-terminator // *ptstrOld = NUL; bResult = BSetPrinterDataBinary( hPrinter, REGVAL_TRAY_FORM_SIZE_PS40, REGVAL_TRAY_FORM_TABLE_PS40, ptstrOldTable, dwOldTableSize); MemFree(ptstrOldTable); return bResult; } #endif // !KERNEL_MODE BOOL BGetDevmodeSettingForOEM( IN PDEVMODE pdm, IN DWORD dwIndex, OUT PVOID pOutput, IN DWORD cbSize, OUT PDWORD pcbNeeded ) /*++ Routine Description: Function to provide OEM plugins access to driver private devmode settings Arguments: pdm - Points to the devmode to be access dwIndex - Predefined index to specify which devmode the caller is interested in pOutput - Points to output buffer cbSize - Size of output buffer pcbNeeded - Returns the expected size of output buffer Return Value: TRUE if successful, FALSE if there is an error --*/ #define MAPPSDEVMODEFIELD(index, field) \ { index, offsetof(PSDRVEXTRA, field), sizeof(pdmPrivate->field) } { PPSDRVEXTRA pdmPrivate; INT i; static const struct { DWORD dwIndex; DWORD dwOffset; DWORD dwSize; } aIndexMap[] = { MAPPSDEVMODEFIELD(OEMGDS_PSDM_FLAGS, dwFlags), MAPPSDEVMODEFIELD(OEMGDS_PSDM_DIALECT, iDialect), MAPPSDEVMODEFIELD(OEMGDS_PSDM_TTDLFMT, iTTDLFmt), MAPPSDEVMODEFIELD(OEMGDS_PSDM_NUP, iLayout), MAPPSDEVMODEFIELD(OEMGDS_PSDM_PSLEVEL, iPSLevel), MAPPSDEVMODEFIELD(OEMGDS_PSDM_CUSTOMSIZE, csdata), { 0, 0, 0 } }; pdmPrivate = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdm); i = 0; while (aIndexMap[i].dwSize != 0) { if (aIndexMap[i].dwIndex == dwIndex) { *pcbNeeded = aIndexMap[i].dwSize; if (cbSize < aIndexMap[i].dwSize || pOutput == NULL) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } CopyMemory(pOutput, (PBYTE) pdmPrivate + aIndexMap[i].dwOffset, aIndexMap[i].dwSize); return TRUE; } i++; } WARNING(("Unknown pscript devmode index: %d\n", dwIndex)); SetLastError(ERROR_NOT_SUPPORTED); return FALSE; } BOOL BConvertPrinterPropertiesData( IN HANDLE hPrinter, IN PRAWBINARYDATA pRawData, OUT PPRINTERDATA pPrinterData, IN PVOID pvSrcData, IN DWORD dwSrcSize ) /*++ Routine Description: Convert an older or newer version PRINTERDATA structure to current version Arguments: hPrinter - Handle to the current printer pRawData - Points to raw printer description data pPrinterData - Points to destination buffer pvSrcData - Points to source data to be converted dwSrcSize - Size of the source data in bytes Return Value: TRUE if conversion was successful, FALSE otherwise Note: This function is called after the library function has already done a generic conversion. --*/ { PPS4_PRINTERDATA pSrc = pvSrcData; PPPDDATA pPpdData; // // Check if the source PRINTERDATA was from NT4 PS driver // pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData); ASSERT(pPpdData != NULL); if (dwSrcSize != sizeof(PS4_PRINTERDATA) || dwSrcSize != pSrc->wSize || pSrc->wDriverVersion != PSDRIVER_VERSION_400 || pSrc->wChecksum != pPpdData->dwNt4Checksum) { return FALSE; } // // Convert PS4 feature/option selections to PS4 format // VConvertOptSelectArray(pRawData, pPrinterData->aOptions, MAX_PRINTER_OPTIONS, pSrc->options, 64, MODE_PRINTER_STICKY); return TRUE; } VOID VUpdatePrivatePrinterData( IN HANDLE hPrinter, IN OUT PPRINTERDATA pPrinterData, IN DWORD dwMode, IN PUIINFO pUIInfo, IN POPTSELECT pCombineOptions ) /*++ Routine Description: Update the Registry with the keyword/value pairs of PRINTERDATA's fixed fields. Arguments: hPrinter - Handle to the current printer pPrinterData - Points to PRINTERDATA dwMode - MODE_READ/MODE_WRITE Return Value: None --*/ { DWORD dwValue, dwMinFreeMem; #ifdef KERNEL_MODE ASSERT(dwMode == MODE_READ); #endif // // read/write PRINTERDATA fields from/to registry // if (dwMode == MODE_READ) { if (BGetPrinterDataDWord(hPrinter, REGVAL_FREEMEM, &dwValue)) { // // REGVAL_FREEMEM is in unit of Kbyte, we need to convert it to byte. // Also make sure the value is not less than the minimum value we required. // dwMinFreeMem = pUIInfo->dwLangLevel < 2 ? MIN_FREEMEM_L1: MIN_FREEMEM_L2; pPrinterData->dwFreeMem = max(dwValue * KBYTES, dwMinFreeMem); } if (BGetPrinterDataDWord(hPrinter, REGVAL_JOBTIMEOUT, &dwValue)) { pPrinterData->dwJobTimeout = dwValue; } if (BGetPrinterDataDWord(hPrinter, REGVAL_PROTOCOL, &dwValue)) { pPrinterData->wProtocol = (WORD)dwValue; if (pPrinterData->wProtocol != PROTOCOL_ASCII && pPrinterData->wProtocol != PROTOCOL_BCP && pPrinterData->wProtocol != PROTOCOL_TBCP && pPrinterData->wProtocol != PROTOCOL_BINARY) { pPrinterData->wProtocol = PROTOCOL_ASCII; } } } #ifndef KERNEL_MODE else { ASSERT(dwMode == MODE_WRITE); // // Remember to convert byte to Kbyte for REGVAL_FREEMEM // (VOID) BSetPrinterDataDWord(hPrinter, REGVAL_FREEMEM, pPrinterData->dwFreeMem / KBYTES); (VOID) BSetPrinterDataDWord(hPrinter, REGVAL_JOBTIMEOUT, pPrinterData->dwJobTimeout); (VOID) BSetPrinterDataDWord(hPrinter, REGVAL_PROTOCOL, (DWORD)pPrinterData->wProtocol); } #endif // !KERNEL_MODE } VOID VDefaultDevmodeFormFields( PUIINFO pUIInfo, PDEVMODE pDevmode, BOOL bMetric ) /*++ Routine Description: Initialized the form-related devmode fields with their default values Arguments: pUIInfo - Points for UIINFO pDevmode - Points to the DEVMODE whose form-related fields are to be initialized bMetric - Specifies whether the system is running in metric mode Return Value: NONE --*/ { ASSERT(pUIInfo); if (!(bMetric && (pUIInfo->dwFlags & FLAG_A4_SIZE_EXISTS)) && !(!bMetric && (pUIInfo->dwFlags & FLAG_LETTER_SIZE_EXISTS))) { PFEATURE pFeature; PPAGESIZE pPageSize; PCWSTR pDisplayName; // // A4 or Letter not available. Use the printer's default paper size. // if ((pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_PAGESIZE)) && (pPageSize = PGetIndexedOption(pUIInfo, pFeature, pFeature->dwDefaultOptIndex)) && (pDisplayName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pPageSize->GenericOption.loDisplayName))) { CopyString(pDevmode->dmFormName, pDisplayName, CCHFORMNAME); pDevmode->dmPaperSize = (short)(pPageSize->dwPaperSizeID); pDevmode->dmPaperWidth = (short)(pPageSize->szPaperSize.cx / DEVMODE_PAPER_UNIT); pDevmode->dmPaperLength = (short)(pPageSize->szPaperSize.cy / DEVMODE_PAPER_UNIT); // // PPD parser always assigns custom paper size values to dwPaperSizeID (see ppdparse.c), including for // standard page sizes, so we need to use dmPaperSize/dmPaperWidth in devmode instead of dmPaperSize. // pDevmode->dmFields |= (DM_FORMNAME | DM_PAPERWIDTH | DM_PAPERLENGTH); pDevmode->dmFields &= ~DM_PAPERSIZE; // // return when we succeeded, otherwise we will fall into the default A4 or Letter case // return; } else { ERR(("Failed to get default paper size from PPD\n")); } } if (bMetric) { CopyString(pDevmode->dmFormName, A4_FORMNAME, CCHFORMNAME); pDevmode->dmPaperSize = DMPAPER_A4; pDevmode->dmPaperWidth = 2100; // 210mm measured in 0.1mm units pDevmode->dmPaperLength = 2970; // 297mm } else { CopyString(pDevmode->dmFormName, LETTER_FORMNAME, CCHFORMNAME); pDevmode->dmPaperSize = DMPAPER_LETTER; pDevmode->dmPaperWidth = 2159; // 8.5" pDevmode->dmPaperLength = 2794; // 11" } pDevmode->dmFields &= ~(DM_PAPERWIDTH | DM_PAPERLENGTH); pDevmode->dmFields |= (DM_PAPERSIZE | DM_FORMNAME); } #if !defined(KERNEL_MODE) || defined(USERMODE_DRIVER) typedef struct _VMERRMSGIDTBL { LANGID lgid; // Language ID DWORD resid; // VM error handler resource ID } VMERRMSGIDTBL, *PVMERRMSGIDTBL; VMERRMSGIDTBL VMErrMsgIDTbl[] = { // Lang. ID Res. ID { LANG_CHINESE, 0 }, // Chinense: use sub table below { LANG_DANISH, PSPROC_vmerr_Danish_ps }, // Danish Adobe bug#342407 { LANG_DUTCH, PSPROC_vmerr_Dutch_ps }, // Dutch { LANG_FINNISH, PSPROC_vmerr_Finnish_ps }, // Finnish Adobe bug#342407 { LANG_FRENCH, PSPROC_vmerr_French_ps }, // French { LANG_GERMAN, PSPROC_vmerr_German_ps }, // German { LANG_ITALIAN, PSPROC_vmerr_Italian_ps }, // Italian { LANG_JAPANESE, PSPROC_vmerr_Japanese_ps }, // Japanese { LANG_KOREAN, PSPROC_vmerr_Korean_ps }, // Korean { LANG_NORWEGIAN, PSPROC_vmerr_Norwegian_ps }, // Norwegian Adobe bug#342407 { LANG_PORTUGUESE, PSPROC_vmerr_Portuguese_ps }, // Portuguese { LANG_SPANISH, PSPROC_vmerr_Spanish_ps }, // Spanish { LANG_SWEDISH, PSPROC_vmerr_Swedish_ps }, // Swedish { 0, 0 } // Stopper. Don't remove this. }; VMERRMSGIDTBL VMErrMsgIDTbl2[] = { // Sub lang. ID Res. ID { SUBLANG_CHINESE_TRADITIONAL, PSPROC_vmerr_TraditionalChinese_ps }, // Taiwan { SUBLANG_CHINESE_SIMPLIFIED, PSPROC_vmerr_SimplifiedChinese_ps }, // PRC { SUBLANG_CHINESE_HONGKONG, PSPROC_vmerr_TraditionalChinese_ps }, // Hong Kong { SUBLANG_CHINESE_SINGAPORE, PSPROC_vmerr_SimplifiedChinese_ps }, // Singapore { 0, 0 } // Stopper. Don't remove this. }; DWORD DWGetVMErrorMessageID( VOID ) /*++ Routine Description: Get the VM Error message ID calculated from the current user's locale. Arguments: None Return Value: The VM Error message ID. --*/ { LANGID lgid; WORD wPrim, wSub; DWORD dwVMErrorMessageID; PVMERRMSGIDTBL pTbl, pTbl2; dwVMErrorMessageID = 0; lgid = GetSystemDefaultLangID(); wPrim = PRIMARYLANGID(lgid); for (pTbl = VMErrMsgIDTbl; pTbl->lgid && !dwVMErrorMessageID; pTbl++) { if (pTbl->lgid == wPrim) { if (pTbl->resid) { dwVMErrorMessageID = pTbl->resid; break; } else { wSub = SUBLANGID(lgid); for (pTbl2 = VMErrMsgIDTbl2; pTbl2->lgid; pTbl2++) { if (pTbl2->lgid == wSub) { dwVMErrorMessageID = pTbl2->resid; break; } } } } } return dwVMErrorMessageID; } #endif // !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)