/*++ Copyright (c) 1996 Microsoft Corporation Module Name: driverui.c Abstract: This file contains utility functions for the UI and the interface to the parser. Environment: Win32 subsystem, DriverUI module, user mode Revision History: 02/09/97 -davidx- Rewrote it to consistently handle common printer info and to clean up parser interface code. 02/04/97 -davidx- Reorganize driver UI to separate ps and uni DLLs. 07/17/96 -amandan- Created it. --*/ #include "precomp.h" HANDLE HCreateHeapForCI(); PCOMMONINFO PLoadCommonInfo( HANDLE hPrinter, PTSTR pPrinterName, DWORD dwFlags ) /*++ Routine Description: Load basic information needed by the driver UI such as: printer driver info level 2 load raw printer description data printer description data instance based on default settings get information about OEM plugins load OEM UI modules Arguments: hPrinter - Handle to the current printer pPrinterName - Points to the current printer name dwFlags - One of the following combinations: 0 FLAG_ALLOCATE_UIDATA FLAG_OPENPRINTER_NORMAL [ | FLAG_OPEN_CONDITIONAL ] FLAG_OPENPRINTER_ADMIN [ | FLAG_INIT_PRINTER ] FLAG_OPENPRINTER_ADMIN [ | FLAG_PROCESS_INIFILE ] Return Value: Pointer to an allocated COMMONINFO structure if successful NULL if there is an error --*/ { static PRINTER_DEFAULTS PrinterDefaults = { NULL, NULL, PRINTER_ALL_ACCESS }; PCOMMONINFO pci; DWORD dwSize; // // Allocate memory for a COMMONINFO structure // dwSize = (dwFlags & FLAG_ALLOCATE_UIDATA) ? sizeof(UIDATA) : sizeof(COMMONINFO); if (! (pci = MemAllocZ(dwSize)) || ! (pci->pPrinterName = DuplicateString(pPrinterName ? pPrinterName : TEXT("NULL")))) { ERR(("Memory allocation failed\n")); VFreeCommonInfo(pci); return NULL; } pci->pvStartSign = pci; pci->dwFlags = dwFlags; // // Check if we should open a handle to the current printer // if (dwFlags & (FLAG_OPENPRINTER_NORMAL | FLAG_OPENPRINTER_ADMIN)) { ASSERT(hPrinter == NULL && pPrinterName != NULL); // // Open a printer handle with the specified access right // if (! OpenPrinter(pPrinterName, &hPrinter, (dwFlags & FLAG_OPENPRINTER_ADMIN) ? &PrinterDefaults : NULL)) { ERR(("OpenPrinter failed for '%ws': %d\n", pPrinterName, GetLastError())); VFreeCommonInfo(pci); return NULL; } pci->hPrinter = hPrinter; } else { ASSERT(hPrinter != NULL); pci->hPrinter = hPrinter; } // // If the caller requires that the printer to be initialized, // check to make sure it is. If not, return error. // if (dwFlags & FLAG_OPEN_CONDITIONAL) { PPRINTER_INFO_2 pPrinterInfo2; DWORD dwInitData; // // NOTE: We're really like to use level 4 here. But due to bug in the // spooler, GetPrinter level 4 doesn't work for printer connections. // dwInitData = gwDriverVersion; #ifdef WINNT_40 // // Hack around spooler bug where DrvConvertDevmode is called before // DrvPrinterEvent.Initialzed is called. // if (!BGetPrinterDataDWord(hPrinter, REGVAL_PRINTER_INITED, &dwInitData)) DrvPrinterEvent(pPrinterName, PRINTER_EVENT_INITIALIZE, 0, 0); #endif if ((pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) == NULL || (pPrinterInfo2->pServerName == NULL) && !BGetPrinterDataDWord(hPrinter, REGVAL_PRINTER_INITED, &dwInitData)) { dwInitData = 0; } MemFree(pPrinterInfo2); if (dwInitData != gwDriverVersion) { TERSE(("Printer not fully initialized yet: %d\n", GetLastError())); VFreeCommonInfo(pci); return NULL; } } // // Get information about the printer driver // if ((pci->pDriverInfo3 = MyGetPrinterDriver(hPrinter, NULL, 3)) == NULL) { ERR(("Cannot get printer driver info: %d\n", GetLastError())); VFreeCommonInfo(pci); return NULL; } // // If FLAG_INIT_PRINTER is set, we should initialize the printer here. // if (dwFlags & (FLAG_INIT_PRINTER | FLAG_PROCESS_INIFILE)) { // // Parse OEM plugin configuration file and // save the resulting info into registry // if (!BProcessPrinterIniFile(hPrinter, pci->pDriverInfo3, NULL, (dwFlags & FLAG_UPGRADE_PRINTER) ? FLAG_INIPROCESS_UPGRADE : 0)) { VERBOSE(("BProcessPrinterIniFile failed\n")); } // // If printer was successfully initialized and caller is not asking to process // ini file only, save a flag in the registry to indicate the fact. // if (dwFlags & FLAG_INIT_PRINTER) { (VOID) BSetPrinterDataDWord(hPrinter, REGVAL_PRINTER_INITED, gwDriverVersion); } } // // fix 317359. In case some part of the driver has changed refresh the .bpd // to update driver-language-specific strings in the .bpd. "Manual Feed" is // written by the parser and therefore the .bpd depends on the language the // parser was localized for. Checking the language would have to be done every time // something is printed, therefore we just delete the .bpd, then the it gets reparsed // always has the same language as the driver. // #ifdef PSCRIPT if (dwFlags & FLAG_REFRESH_PARSED_DATA) { DeleteRawBinaryData(pci->pDriverInfo3->pDataFile); } #endif // // Load raw binary printer description data, and // Get a printer description data instance using the default settings // // Notice that this is done inside a critical section (because // GPD parsers has lots of globals). // // ENTER_CRITICAL_SECTION(); pci->pRawData = LoadRawBinaryData(pci->pDriverInfo3->pDataFile); if (pci->pRawData) pci->pInfoHeader = InitBinaryData(pci->pRawData, NULL, NULL); if (pci->pInfoHeader) pci->pUIInfo = OFFSET_TO_POINTER(pci->pInfoHeader, pci->pInfoHeader->loUIInfoOffset); // LEAVE_CRITICAL_SECTION(); if (!pci->pRawData || !pci->pInfoHeader || !pci->pUIInfo) { ERR(("Cannot load printer description data: %d\n", GetLastError())); VFreeCommonInfo(pci); return NULL; } // // Get information about OEM plugins and load them // if (! (pci->pOemPlugins = PGetOemPluginInfo(hPrinter, pci->pDriverInfo3->pConfigFile, pci->pDriverInfo3)) || ! BLoadOEMPluginModules(pci->pOemPlugins)) { ERR(("Cannot load OEM plugins: %d\n", GetLastError())); VFreeCommonInfo(pci); return NULL; } pci->oemuiobj.cbSize = sizeof(OEMUIOBJ); pci->oemuiobj.pOemUIProcs = (POEMUIPROCS) &OemUIHelperFuncs; pci->pOemPlugins->pdriverobj = &pci->oemuiobj; return pci; } VOID VFreeCommonInfo( PCOMMONINFO pci ) /*++ Routine Description: Release common information used by the driver UI Arguments: pci - Common driver information to be released Return Value: NONE --*/ { if (pci == NULL) return; // // Unload OEM UI modules and free OEM plugin info // if (pci->pOemPlugins) VFreeOemPluginInfo(pci->pOemPlugins); // // Unload raw binary printer description data // and/or any printer description data instance // if (pci->pInfoHeader) FreeBinaryData(pci->pInfoHeader); if (pci->pRawData) UnloadRawBinaryData(pci->pRawData); // // Close the printer handle if it was opened by us // if ((pci->dwFlags & (FLAG_OPENPRINTER_NORMAL|FLAG_OPENPRINTER_ADMIN)) && (pci->hPrinter != NULL)) { ClosePrinter(pci->hPrinter); } #ifdef UNIDRV if (pci->pWinResData) { VWinResClose(pci->pWinResData); MemFree(pci->pWinResData); } #endif if (pci->hHeap) HeapDestroy(pci->hHeap); MemFree(pci->pSplForms); MemFree(pci->pCombinedOptions); MemFree(pci->pPrinterData); MemFree(pci->pPrinterName); MemFree(pci->pDriverInfo3); MemFree(pci->pdm); MemFree(pci); } BOOL BFillCommonInfoDevmode( PCOMMONINFO pci, PDEVMODE pdmPrinter, PDEVMODE pdmInput ) /*++ Routine Description: Populate the devmode fields in the COMMONINFO structure. start out with the driver default devmode, and merge it with the printer default devmode, and merge it with the input devmode Arguments: pci - Points to a COMMONINFO structure pdmPrinter - Points to printer default devmode pdmInput - Points to input devmode Return Value: TRUE if successful, FALSE if there is an error Note: pdmPrinter and/or pdmInput can be NULL. --*/ { // // Start with driver default devmode // ASSERT(pci->pdm == NULL); pci->pdm = PGetDefaultDevmodeWithOemPlugins( pci->pPrinterName, pci->pUIInfo, pci->pRawData, IsMetricCountry(), pci->pOemPlugins, pci->hPrinter); // // Merge with printer default and input devmode // if (! pci->pdm || ! BValidateAndMergeDevmodeWithOemPlugins( pci->pdm, pci->pUIInfo, pci->pRawData, pdmPrinter, pci->pOemPlugins, pci->hPrinter) || ! BValidateAndMergeDevmodeWithOemPlugins( pci->pdm, pci->pUIInfo, pci->pRawData, pdmInput, pci->pOemPlugins, pci->hPrinter)) { ERR(("Cannot process devmode information: %d\n", GetLastError())); return FALSE; } pci->pdmPrivate = (PDRIVEREXTRA) GET_DRIVER_PRIVATE_DEVMODE(pci->pdm); return TRUE; } BOOL BFillCommonInfoPrinterData( PCOMMONINFO pci ) /*++ Routine Description: Populate the printer-sticky property data field Arguments: pci - Points to basic printer info Return Value: TRUE if successful, FALSE if there is an error --*/ { ASSERT(pci->pPrinterData == NULL); if (pci->pPrinterData = MemAllocZ(sizeof(PRINTERDATA))) return BGetPrinterProperties(pci->hPrinter, pci->pRawData, pci->pPrinterData); ERR(("Memory allocation failed\n")); return FALSE; } BOOL BCombineCommonInfoOptionsArray( PCOMMONINFO pci ) /*++ Routine Description: Combined document-sticky feature selections and printer-sticky feature selection into a single options array Arguments: pci - Points to basic printer info Return Value: TRUE if successful, FALSE if there is an error --*/ { POPTSELECT pDocOptions, pPrinterOptions; #ifdef UNIDRV OPTSELECT DocOptions[MAX_PRINTER_OPTIONS]; OPTSELECT PrinterOptions[MAX_PRINTER_OPTIONS]; #endif // // Allocate enough memory for the combined options array // pci->pCombinedOptions = MemAllocZ(sizeof(OPTSELECT) * MAX_COMBINED_OPTIONS); if (pci->pCombinedOptions == NULL) { ERR(("Memory allocation failed\n")); return FALSE; } pDocOptions = pci->pdm ? PGetDevmodeOptionsArray(pci->pdm) : NULL; pPrinterOptions = pci->pPrinterData ? pci->pPrinterData->aOptions : NULL; #ifdef UNIDRV // // GPD parser doesn't follow the current parser interface spec. // It AVs if either doc- or printer-sticky options array is NULL. // So we have to call it first to get appropriate default options first. // if (pDocOptions == NULL) { if (! InitDefaultOptions(pci->pRawData, DocOptions, MAX_PRINTER_OPTIONS, MODE_DOCUMENT_STICKY)) { return FALSE; } pDocOptions = DocOptions; } if (pPrinterOptions == NULL) { if (! InitDefaultOptions(pci->pRawData, PrinterOptions, MAX_PRINTER_OPTIONS, MODE_PRINTER_STICKY)) { return FALSE; } pPrinterOptions = PrinterOptions; } #endif // UNIDRV return CombineOptionArray(pci->pRawData, pci->pCombinedOptions, MAX_COMBINED_OPTIONS, pDocOptions, pPrinterOptions); } VOID VFixOptionsArrayWithPaperSizeID( PCOMMONINFO pci ) /*++ Routine Description: Fix up combined options array with paper size information from public devmode fields Arguments: pci - Points to basic printer info Return Value: NONE --*/ { PFEATURE pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE); BOOL abEnabledOptions[MAX_PRINTER_OPTIONS]; PDWORD pdwPaperIndex = (PDWORD)&abEnabledOptions; DWORD dwCount, dwOptionIndex, i; WCHAR awchBuf[CCHPAPERNAME]; if (pFeature == NULL) return; dwCount = MapToDeviceOptIndex(pci->pInfoHeader, GID_PAGESIZE, pci->pdm->dmPaperWidth * DEVMODE_PAPER_UNIT, pci->pdm->dmPaperLength * DEVMODE_PAPER_UNIT, pdwPaperIndex); if (dwCount == 0 ) return; if (dwCount > 1 ) { PPAGESIZE pPageSize; for (i = 0; i < dwCount; i++) { if (pPageSize = (PPAGESIZE)PGetIndexedOption(pci->pUIInfo, pFeature, pdwPaperIndex[i])) { if ((LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, awchBuf, CCHPAPERNAME)) && (_wcsicmp(pci->pdm->dmFormName, awchBuf) == EQUAL_STRING) ) { dwOptionIndex = pdwPaperIndex[i]; break; } } } if (i >= dwCount) dwOptionIndex = pdwPaperIndex[0]; } else dwOptionIndex = pdwPaperIndex[0]; ZeroMemory(abEnabledOptions, sizeof(abEnabledOptions)); abEnabledOptions[dwOptionIndex] = TRUE; ReconstructOptionArray(pci->pRawData, pci->pCombinedOptions, MAX_COMBINED_OPTIONS, GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature), abEnabledOptions); } VOID VFixOptionsArrayWithDevmode( PCOMMONINFO pci ) /*++ Routine Description: Fix up combined options array with information from public devmode fields Arguments: pci - Points to basic printer info Return Value: NONE --*/ { // // Mapping table from public devmode fields to GID indices // We assume that GID_COLORMODE corresponds to DM_COLR // static CONST struct _DMFIELDS_GID_MAPPING { DWORD dwGid; DWORD dwMask; } DMFieldsGIDMapping[] = { { GID_RESOLUTION, DM_PRINTQUALITY|DM_YRESOLUTION }, { GID_PAGESIZE, DM_FORMNAME|DM_PAPERSIZE|DM_PAPERWIDTH|DM_PAPERLENGTH }, { GID_DUPLEX, DM_DUPLEX }, { GID_INPUTSLOT, DM_DEFAULTSOURCE }, { GID_MEDIATYPE, DM_MEDIATYPE }, { GID_ORIENTATION, DM_ORIENTATION }, { GID_COLLATE, DM_COLLATE }, { GID_COLORMODE, DM_COLOR }, }; INT iIndex; BOOL bConflict; // // Validate form-related devmode fields // if (pci->pSplForms == NULL) pci->pSplForms = MyEnumForms(pci->hPrinter, 1, &pci->dwSplForms); if (! BValidateDevmodeCustomPageSizeFields( pci->pRawData, pci->pUIInfo, pci->pdm, NULL) && ! BValidateDevmodeFormFields( pci->hPrinter, pci->pdm, NULL, pci->pSplForms, pci->dwSplForms)) { VDefaultDevmodeFormFields(pci->pUIInfo, pci->pdm, IsMetricCountry()); } // // Fix up options array with information from public devmode fields // iIndex = sizeof(DMFieldsGIDMapping) / sizeof(struct _DMFIELDS_GID_MAPPING); while (iIndex-- > 0) { if (pci->pdm->dmFields & DMFieldsGIDMapping[iIndex].dwMask) { #if UNIDRV if (DMFieldsGIDMapping[iIndex].dwGid == GID_PAGESIZE) { VFixOptionsArrayWithPaperSizeID(pci); } else #endif { (VOID) ChangeOptionsViaID(pci->pInfoHeader, pci->pCombinedOptions, DMFieldsGIDMapping[iIndex].dwGid, pci->pdm); } } } } BOOL BUpdateUIInfo( PCOMMONINFO pci ) /*++ Routine Description: Get an updated printer description data instance using the combined options array Arguments: pci - Points to basic printer info Return Value: TRUE if successful, FALSE if there is an error --*/ { PINFOHEADER pInfoHeader; // // Get an updated instance of printer description data // pInfoHeader = UpdateBinaryData(pci->pRawData, pci->pInfoHeader, pci->pCombinedOptions); if (pInfoHeader == NULL) { ERR(("UpdateBinaryData failed\n")); return FALSE; } // // Reset various points in COMMONINFO structure // pci->pInfoHeader = pInfoHeader; pci->pUIInfo = OFFSET_TO_POINTER(pInfoHeader, pInfoHeader->loUIInfoOffset); ASSERT(pci->pUIInfo != NULL); return (pci->pUIInfo != NULL); } BOOL BPrepareForLoadingResource( PCOMMONINFO pci, BOOL bNeedHeap ) /*++ Routine Description: Make sure a heap is created and the resource DLL has been loaded Arguments: pci - Points to basic printer info bNeedHeap - Whether memory heap is necessary Return Value: TRUE if successful, FALSE if there is an error --*/ { BOOL bResult = FALSE; // // Create the memory heap if necessary // if ( bNeedHeap && ! pci->hHeap && ! (pci->hHeap = HCreateHeapForCI())) { return bResult; } #ifdef UNIDRV if (pci->pWinResData) { bResult = TRUE; } else { if ((pci->pWinResData = MemAllocZ(sizeof(WINRESDATA))) && (BInitWinResData(pci->pWinResData, pci->pDriverInfo3->pDriverPath, pci->pUIInfo))) bResult = TRUE; } #endif return bResult; } #ifndef PSCRIPT PWSTR PGetReadOnlyDisplayName( PCOMMONINFO pci, PTRREF loOffset ) /*++ Routine Description: Get a read-only copy of a display name: 1) if the display name is in the binary printer description data, then we simply return a pointer to that data. 2) otherwise, the display name is in the resource DLL. we allocate memory out of the driver's heap and load the string. Caller should NOT free the returned pointer. The memory will go away when the binary printer description data is unloaded or when the driver's heap is destroyed. Arguments: pci - Points to basic printer info loOffset - Display name string offset Return Value: Pointer to the requested display name string NULL if there is an error --*/ { if (loOffset & GET_RESOURCE_FROM_DLL) { // // loOffset specifies a string resource ID // in the resource DLL // WCHAR wchbuf[MAX_DISPLAY_NAME]; INT iLength; PWSTR pwstr; HANDLE hResDll; DWORD dwResID = loOffset & ~GET_RESOURCE_FROM_DLL; // // First ensure the resource DLL has been loaded // and a heap has already been created // if (! BPrepareForLoadingResource(pci, TRUE)) return NULL; // // Load string resource into a temporary buffer // and allocate enough memory to hold the string // iLength = ILOADSTRING(pci, dwResID, wchbuf, MAX_DISPLAY_NAME); pwstr = HEAPALLOC(pci->hHeap, (iLength+1) * sizeof(WCHAR)); if (pwstr == NULL) { ERR(("Memory allocation failed\n")); return NULL; } // // Copy the string to allocated memory and // return a pointer to it. // CopyMemory(pwstr, wchbuf, iLength*sizeof(WCHAR)); return pwstr; } else { // // loOffset is a byte offset from the beginning of // the resource data block // return OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData, loOffset); } } #endif // !PSCRIPT BOOL BLoadDisplayNameString( PCOMMONINFO pci, PTRREF loOffset, PWSTR pwstrBuf, INT iMaxChars ) /*++ Routine Description: This function is similar to PGetReadOnlyDisplayName but the caller must provide the buffer for loading the string. Arguments: pci - Points to basic printer info loOffset - Display name string offset pwstrBuf - Points to buffer for storing loaded display name string iMaxChars - Size of output buffer in characters Return Value: TRUE if successful, FALSE if there is an error --*/ { ASSERT(pwstrBuf && iMaxChars > 0); pwstrBuf[0] = NUL; if (loOffset & GET_RESOURCE_FROM_DLL) { // // loOffset specifies a string resource ID // in the resource DLL // INT iLength; HANDLE hResDll; DWORD dwResID = loOffset & ~GET_RESOURCE_FROM_DLL; // // First ensure the resource DLL has been loaded // if (! BPrepareForLoadingResource(pci, FALSE)) return FALSE; // // Load string resource into the output buffer // and allocate enough memory to hold the string // iLength = ILOADSTRING(pci, dwResID, pwstrBuf, (WORD)iMaxChars); return (iLength > 0); } else { // // loOffset is a byte offset from the beginning of // the resource data block // PWSTR pwstr; pwstr = OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData, loOffset); if (pwstr == NULL) return FALSE; CopyString(pwstrBuf, pwstr, iMaxChars); return TRUE; } } BOOL BLoadPageSizeNameString( PCOMMONINFO pci, PTRREF loOffset, PWSTR pwstrBuf, INT iMaxChars, INT iStdId ) /*++ Routine Description: This function is similar to PGetReadOnlyDisplayName but the caller must provide the buffer for loading the string. Arguments: pci - Points to basic printer info loOffset - Display name string offset pwstrBuf - Points to buffer for storing loaded display name string iMaxChars - Size of output buffer in characters iStdId - Predefined standard ID for page size, e.g. DMPAPER_XXX Return Value: TRUE if successful, FALSE if there is an error --*/ { ASSERT(pwstrBuf && iMaxChars > 0); pwstrBuf[0] = NUL; if (loOffset == USE_SYSTEM_NAME) { PFORM_INFO_1 pForm; INT iIndex = iStdId - DMPAPER_FIRST; // // iIndex is zero based. // if (pci->pSplForms == NULL || (INT)pci->dwSplForms <= iIndex) { WARNING(("BLoadPageSizeName, use std name, pSplForms is NULL \n")); return FALSE; } pForm = pci->pSplForms + iIndex; CopyString(pwstrBuf, pForm->pName, iMaxChars); return (TRUE); } else return (BLoadDisplayNameString(pci, loOffset, pwstrBuf, iMaxChars)); } ULONG_PTR HLoadIconFromResourceDLL( PCOMMONINFO pci, DWORD dwIconID ) /*++ Routine Description: Load icon resource from the resource DLL Arguments: pci - Points to common printer info dwIconID - Specifies ID of the icon to be loaded Return Value: Handle to the specified icon resource 0 if the specified icon cannot be loaded --*/ { // // First ensure the resource DLL has been loaded // #ifdef UNIDRV RES_ELEM ResElem; ULONG_PTR pRes; if (! BPrepareForLoadingResource(pci, FALSE)) return 0; if (BGetWinRes(pci->pWinResData, (PQUALNAMEEX)&dwIconID, (INT)((ULONG_PTR)RT_ICON), &ResElem)) return ((ULONG_PTR)(ResElem.pvResData)); #endif return 0; } PUIDATA PFillUiData( HANDLE hPrinter, PTSTR pPrinterName, PDEVMODE pdmInput, INT iMode ) /*++ Routine Description: This function is called by DrvDocumentPropertySheets and DrvPrinterPropertySheets. It allocates and initializes a UIDATA structure that's used to display property pages. Arguments: hPrinter - Handle to the current printer pPrinterName - Name of the current printer pdmInput - Input devmode iMode - Identify the caller: MODE_DOCUMENT_STICKY - called from DrvDocumentPropertySheets MODE_PRINTER_STICY - called from DrvPrinterPropertySheets Return Value: Pointer to a UIDATA structure, NULL if there is an error --*/ { PUIDATA pUiData; PCOMMONINFO pci; BOOL bNupOption; PFEATURE pFeature; DWORD dwFeatureIndex, dwOptionIndexOld, dwOptionIndexNew; BOOL bUpdateFormField; // // Allocate UIDATA structure and load common information // pUiData = (PUIDATA) PLoadCommonInfo(hPrinter, pPrinterName, FLAG_ALLOCATE_UIDATA); if (pUiData == NULL) goto fill_uidata_err; pUiData->pvEndSign = pUiData; pUiData->iMode = iMode; pci = &pUiData->ci; // // Create a memory heap // if ((pci->hHeap = HCreateHeapForCI()) == NULL) goto fill_uidata_err; // // Get printer-sticky property data // if (! BFillCommonInfoPrinterData(pci)) goto fill_uidata_err; // // If called from DrvDocumentPropertySheets, then process // devmode information: driver default + printer default + input devmode // if (iMode == MODE_DOCUMENT_STICKY) { PPRINTER_INFO_2 pPrinterInfo2; if (! (pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) || ! BFillCommonInfoDevmode(pci, pPrinterInfo2->pDevMode, pdmInput)) { MemFree(pPrinterInfo2); goto fill_uidata_err; } MemFree(pPrinterInfo2); } // // Merge doc-sticky and printer-sticky option selections // if (! BCombineCommonInfoOptionsArray(pci)) goto fill_uidata_err; // // If called from DrvDocumentPropertySheets, // fix up combined options with public devmode information // if (iMode == MODE_DOCUMENT_STICKY) { VFixOptionsArrayWithDevmode(pci); // // Remember the paper size option parser picked to support the devmode form // if ((pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE)) == NULL) { ASSERT(FALSE); goto fill_uidata_err; } dwFeatureIndex = GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature); dwOptionIndexOld = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex; } VGetSpoolerEmfCaps(pci->hPrinter, &bNupOption, &pUiData->bEMFSpooling, 0, NULL); // // Resolve any conflicts between printer feature selections, // and get an updated printer description data instance // using the combined options array. // (VOID) ResolveUIConflicts(pci->pRawData, pci->pCombinedOptions, MAX_COMBINED_OPTIONS, iMode == MODE_PRINTER_STICKY ? iMode : MODE_DOCANDPRINTER_STICKY); if (iMode == MODE_DOCUMENT_STICKY) { dwOptionIndexNew = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex; bUpdateFormField = FALSE; if (dwOptionIndexNew != dwOptionIndexOld) { // // Constraint resolving has changed page size selection, so we need // to update devmode's form fields. // bUpdateFormField = TRUE; } else { FORM_INFO_1 *pForm = NULL; // // Unless the form requested by devmode is not supported on the printer, // we still want to show the original form name in upcoming doc-setting UI. // For example, if input devmode requested "Legal", parser maps it to option // "OEM Legal", but both "Legal" and "OEM Legal" will be shown as supported // forms on the printer, then we should still show "Legal" instead of "OEM Legal" // in UI's PageSize list. However, if input devmode requestd "8.5 x 12", which // won't be shown as a supportd form and it's mapped to "OEM Legal", then we should // show "OEM Legal". // // // pdm->dmFormName won't have a valid form name for custom page size (see // BValidateDevmodeFormFields()). VOptionsToDevmodeFields() knows to handle that. // if ((pci->pdm->dmFields & DM_FORMNAME) && (pForm = MyGetForm(pci->hPrinter, pci->pdm->dmFormName, 1)) && !BFormSupportedOnPrinter(pci, pForm, &dwOptionIndexNew)) { bUpdateFormField = TRUE; } MemFree(pForm); } VOptionsToDevmodeFields(pci, bUpdateFormField); } if (BUpdateUIInfo(pci)) { // // Set the flag to indicate we are within the property sheet session. This flag will // be used by new helper function interface to determine whether the helper function // is available or not. // pci->dwFlags |= FLAG_PROPSHEET_SESSION; return pUiData; } fill_uidata_err: ERR(("PFillUiData failed: %d\n", GetLastError())); VFreeUiData(pUiData); return NULL; } PTSTR PtstrDuplicateStringFromHeap( IN PTSTR ptstrSrc, IN HANDLE hHeap ) /*++ Routine Description: Duplicate a Unicode string Arguments: pwstrUnicodeString - Pointer to the input Unicode string hHeap - Handle to a heap from which to allocate memory Return Value: Pointer to the resulting Unicode string NULL if there is an error --*/ { PTSTR ptstrDest; INT iSize; if (ptstrSrc == NULL) return NULL; iSize = SIZE_OF_STRING(ptstrSrc); if (ptstrDest = HEAPALLOC(hHeap, iSize)) CopyMemory(ptstrDest, ptstrSrc, iSize); else ERR(("Couldn't duplicate string: %ws\n", ptstrSrc)); return ptstrDest; } POPTITEM PFindOptItemWithKeyword( IN PUIDATA pUiData, IN PCSTR pKeywordName ) /*++ Routine Description: Find the OPTITEM with UserData's pKeywordName matching given keyword name Arguments: pUiData - Points to UIDATA structure pKeywordName - Specifies the keyword name needs to be matched Return Value: Pointer to the specified OPTITEM, NULL if no such item is found --*/ { DWORD dwCount; POPTITEM pOptItem; ASSERT(VALIDUIDATA(pUiData)); pOptItem = pUiData->pDrvOptItem; dwCount = pUiData->dwDrvOptItem; while (dwCount--) { if (((PUSERDATA)pOptItem->UserData)->pKeyWordName != NULL && strcmp(((PUSERDATA)pOptItem->UserData)->pKeyWordName, pKeywordName) == EQUAL_STRING) return pOptItem; pOptItem++; } return NULL; } POPTITEM PFindOptItemWithUserData( IN PUIDATA pUiData, IN DWORD UserData ) /*++ Routine Description: Find the OPTITEM containing the specified UserData value Arguments: pUiData - Points to UIDATA structure UserData - Specifies the interested UserData value Return Value: Pointer to the specified OPTITEM, NULL if no such item is found --*/ { DWORD dwCount; POPTITEM pOptItem; ASSERT(VALIDUIDATA(pUiData)); pOptItem = pUiData->pDrvOptItem; dwCount = pUiData->dwDrvOptItem; while (dwCount--) { if (GETUSERDATAITEM(pOptItem->UserData) == UserData) return pOptItem; pOptItem++; } return NULL; } #ifndef WINNT_40 VOID VNotifyDSOfUpdate( IN HANDLE hPrinter ) /*++ Routine Description: Call SetPrinter to notify the DS of the update of driver attribute Arguments: hPrinter - Handle to the current printer Return Value: NONE --*/ { PRINTER_INFO_7 PrinterInfo7; ZeroMemory(&PrinterInfo7, sizeof(PrinterInfo7)); PrinterInfo7.dwAction = DSPRINT_UPDATE; // // Comments from spooler DS developer: // // In the beginning, SetPrinter did not fail with ERROR_IO_PENDING. // Then it was modified and would occasionally fail with this error. // Finally, for performance reasons, it was modified again and now // almost always fails with this error (there are situations where // it will succeed). // if (!SetPrinter(hPrinter, 7, (PBYTE) &PrinterInfo7, 0) && (GetLastError() != ERROR_IO_PENDING)) { WARNING(("Couldn't publish printer info into DS\n")); } } #endif HANDLE HCreateHeapForCI() { HANDLE hHeap; if(!(hHeap = HeapCreate(0, 8192, 0))) { ERR(("CreateHeap failed: %d\n", GetLastError())); } return hHeap; } #ifndef WINNT_40 BOOL DrvQueryColorProfile( HANDLE hPrinter, PDEVMODEW pdmSrc, ULONG ulQueryMode, VOID *pvProfileData, ULONG *pcbProfileData, FLONG *pflProfileData ) /*++ Routine Description: Call the OEM to let them determine the default color profile. Arguments: hPrinter - Handle to printer pdmSrc - Input devmode ulQueryMode - query mode pvProfileData - Buffer for profile data pcbProfileData - Size of profile data buffer pflProfileData - other profile info Return Value: TRUE for success and FALSE for failure --*/ { PFN_OEMQueryColorProfile pfnQueryColorProfile; PCOMMONINFO pci; BOOL bRc = FALSE; if (! (pci = PLoadCommonInfo(hPrinter, NULL, 0)) || ! BFillCommonInfoDevmode(pci, NULL, pdmSrc) || ! BCombineCommonInfoOptionsArray(pci)) { WARNING(("Could not get PCI in DrvQueryColorProfile\n")); VFreeCommonInfo(pci); return FALSE; } VFixOptionsArrayWithDevmode(pci); (VOID) ResolveUIConflicts(pci->pRawData, pci->pCombinedOptions, MAX_COMBINED_OPTIONS, MODE_DOCUMENT_STICKY); VOptionsToDevmodeFields(pci, TRUE); if (! BUpdateUIInfo(pci)) { VFreeCommonInfo(pci); return FALSE; } // // If OEM plugin returns a profile, give it back, otherwise return FALSE // FOREACH_OEMPLUGIN_LOOP(pci) if (HAS_COM_INTERFACE(pOemEntry)) { HRESULT hr; hr = HComOEMQUeryColorProfile(pOemEntry, hPrinter, &pci->oemuiobj, pci->pdm, pOemEntry->pOEMDM, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData ); if (hr == E_NOTIMPL) continue; bRc = SUCCEEDED(hr); } else { pfnQueryColorProfile = GET_OEM_ENTRYPOINT(pOemEntry, OEMQueryColorProfile); if (pfnQueryColorProfile) { bRc = (*pfnQueryColorProfile)(hPrinter, &pci->oemuiobj, pci->pdm, pOemEntry->pOEMDM, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData ); } } if (bRc) break; END_OEMPLUGIN_LOOP VFreeCommonInfo(pci); return bRc; } #else // ifndef WINNT_40 BOOL DrvQueryColorProfile( HANDLE hPrinter, PDEVMODEW pdmSrc, ULONG ulQueryMode, VOID *pvProfileData, ULONG *pcbProfileData, FLONG *pflProfileData ) /*++ Routine Description: Call the OEM to let them determine the default color profile. Arguments: hPrinter - Handle to printer pdmSrc - Input devmode ulQueryMode - query mode pvProfileData - Buffer for profile data pcbProfileData - Size of profile data buffer pflProfileData - other profile info Return Value: TRUE for success and FALSE for failure --*/ { return TRUE; } #endif // WINNT_40