/*++ Copyright (c) 1996 Microsoft Corporation Module Name: docprop.c Abstract: This file handles the DrvDocumentProperties and DrvDocumentPropertySheets spooler API Environment: Win32 subsystem, DriverUI module, user mode Revision History: 02/13/97 -davidx- Implement OEM plugin support. 02/13/97 -davidx- Working only with options array internally. 02/10/97 -davidx- Consistent handling of common printer info. 02/04/97 -davidx- Reorganize driver UI to separate ps and uni DLLs. 07/17/96 -amandan- Created it. --*/ #include "precomp.h" // // Local and external function declarations // LONG LSimpleDocumentProperties( PDOCUMENTPROPERTYHEADER); CPSUICALLBACK cpcbDocumentPropertyCallback(PCPSUICBPARAM); BOOL BGetPageOrderFlag(PCOMMONINFO); VOID VUpdateEmfFeatureItems(PUIDATA, BOOL); VOID VUpdateBookletOption(PUIDATA , POPTITEM); LONG DrvDocumentPropertySheets( PPROPSHEETUI_INFO pPSUIInfo, LPARAM lParam ) /*++ Routine Description: This function is called to add the Document Property Page to the specified property sheets and/or to update the document properties. If pPSUIInfo is NULL, it performs the operation specified by the fMode flag of DOCUMENTPROPERTYHEADER. Specifically, if flMode is zero or pDPHdr->pdmOut is NULL, return the size of DEVMODE. If pPSUInfo is not NULL: pPSUIInf->Reason REASON_INIT- fills PCOMPROPSHEETUI with document UI items calls compstui to add the page. REASON_GET_INFO_HEADER - fills out PROPSHEETUI_INFO. REASON_SET_RESULT - saves devmode settings and copy the devmode into output buffer. REASON_DESTROY - Cleans up. Arguments: pSUIInfo - pointer to PPROPSHEETUI_INFO lParam - varies depending on the reason this function is called Return Value: > 0 success <= 0 for failure --*/ { PDOCUMENTPROPERTYHEADER pDPHdr; PCOMPROPSHEETUI pCompstui; PUIDATA pUiData; PDLGPAGE pDlgPage; LONG lRet; BOOL bResult=FALSE; // // Validate input parameters // if (! (pDPHdr = (PDOCUMENTPROPERTYHEADER) (pPSUIInfo ? pPSUIInfo->lParamInit : lParam))) { RIP(("DrvDocumentPropertySheets: invalid parameters\n")); return -1; } // // pPSUIInfo = NULL, the caller is spooler so just handle the simple case, // no display is necessary. // if (pPSUIInfo == NULL) return LSimpleDocumentProperties(pDPHdr); // // Create a UIDATA structure if necessary // if (pPSUIInfo->Reason == PROPSHEETUI_REASON_INIT) { pUiData = PFillUiData(pDPHdr->hPrinter, pDPHdr->pszPrinterName, pDPHdr->pdmIn, MODE_DOCUMENT_STICKY); } else pUiData = (PUIDATA) pPSUIInfo->UserData; // // Validate pUiData // if (pUiData == NULL) { ERR(("UIDATA is NULL\n")); return -1; } ASSERT(VALIDUIDATA(pUiData)); // // Handle various cases for which this function might be called // switch (pPSUIInfo->Reason) { case PROPSHEETUI_REASON_INIT: // // Allocate memory and partially fill out various data // structures required to call common UI routine. // pDlgPage = (pDPHdr->fMode & DM_ADVANCED) ? CPSUI_PDLGPAGE_ADVDOCPROP : CPSUI_PDLGPAGE_DOCPROP; pUiData->bPermission = ((pDPHdr->fMode & DM_NOPERMISSION) == 0); #ifdef PSCRIPT FOREACH_OEMPLUGIN_LOOP((&(pUiData->ci))) if (HAS_COM_INTERFACE(pOemEntry)) { HRESULT hr; hr = HComOEMHideStandardUI(pOemEntry, OEMCUIP_DOCPROP); // // In the case when multiple plugins are chained, it doesn't // make sense for one plugin to hide standard UI when another // one still wants to use the standard UI. So as long as one // plugin returns S_OK here, we will hide the standard UI. // if (bResult = SUCCEEDED(hr)) break; } END_OEMPLUGIN_LOOP #endif // PSCRIPT if (bResult) { // // Set the flag to indicate plugin is hiding our standard // document property sheet UI. // pUiData->dwHideFlags |= HIDEFLAG_HIDE_STD_DOCPROP; pUiData->pfnComPropSheet = pPSUIInfo->pfnComPropSheet; pUiData->hComPropSheet = pPSUIInfo->hComPropSheet; if (BAddOemPluginPages(pUiData, pDPHdr->fMode)) { pPSUIInfo->UserData = (ULONG_PTR) pUiData; pPSUIInfo->Result = CPSUI_CANCEL; lRet = 1; break; } } else if (pCompstui = PPrepareDataForCommonUI(pUiData, pDlgPage)) { #ifdef UNIDRV VMakeMacroSelections(pUiData, NULL); #endif pCompstui->pfnCallBack = cpcbDocumentPropertyCallback; pUiData->pfnComPropSheet = pPSUIInfo->pfnComPropSheet; pUiData->hComPropSheet = pPSUIInfo->hComPropSheet; pUiData->pCompstui = pCompstui; // // Indicate which items are constrained // VPropShowConstraints(pUiData, MODE_DOCANDPRINTER_STICKY); // // Call common UI library to add our pages // if (pUiData->pfnComPropSheet(pUiData->hComPropSheet, CPSFUNC_ADD_PCOMPROPSHEETUI, (LPARAM) pCompstui, (LPARAM) &lRet) && BAddOemPluginPages(pUiData, pDPHdr->fMode)) { pPSUIInfo->UserData = (ULONG_PTR) pUiData; pPSUIInfo->Result = CPSUI_CANCEL; lRet = 1; break; } } // // Clean up in the case of error // ERR(("Failed to initialize property sheets\n")); VFreeUiData(pUiData); return -1; case PROPSHEETUI_REASON_GET_INFO_HEADER: { PPROPSHEETUI_INFO_HEADER pPSUIHdr; DWORD dwIcon; pPSUIHdr = (PPROPSHEETUI_INFO_HEADER) lParam; pPSUIHdr->Flags = PSUIHDRF_PROPTITLE | PSUIHDRF_NOAPPLYNOW; pPSUIHdr->pTitle = pUiData->ci.pPrinterName; pPSUIHdr->hInst = ghInstance; // // Use the Icon specified in the binary data as // the printer icon. // dwIcon = pUiData->ci.pUIInfo->loPrinterIcon; if (dwIcon && (pPSUIHdr->IconID = HLoadIconFromResourceDLL(&pUiData->ci, dwIcon))) pPSUIHdr->Flags |= PSUIHDRF_USEHICON; else pPSUIHdr->IconID = _DwGetPrinterIconID(); } lRet = 1; break; case PROPSHEETUI_REASON_SET_RESULT: // // Copy the new devmode back into the output buffer provided by the caller // Always return the smaller of current and input devmode // { PSETRESULT_INFO pSRInfo = (PSETRESULT_INFO) lParam; if ((pSRInfo->Result == CPSUI_OK) && (pDPHdr->pdmOut != NULL) && (pDPHdr->fMode & (DM_COPY | DM_UPDATE))) { PCOMMONINFO pci = (PCOMMONINFO)pUiData; // // CPSUICB_REASON_APPLYNOW may not have been called. If so, we need // to perform tasks that are usually done by CPSUICB_REASON_APPLYNOW // case in our callback function cpcbDocumentPropertyCallback. // if (!(pci->dwFlags & FLAG_APPLYNOW_CALLED)) { OPTSELECT OldCombinedOptions[MAX_COMBINED_OPTIONS]; // // Save a copy the pre-resolve option array // CopyMemory(OldCombinedOptions, pci->pCombinedOptions, MAX_COMBINED_OPTIONS * sizeof(OPTSELECT)); // // Call the parsers to resolve any remaining conflicts. // ResolveUIConflicts(pci->pRawData, pci->pCombinedOptions, MAX_COMBINED_OPTIONS, MODE_DOCANDPRINTER_STICKY); // // Update the OPTITEM list to match the updated options array // VUpdateOptItemList(pUiData, OldCombinedOptions, pci->pCombinedOptions); // // Transfer information from options array to public devmode fields // VOptionsToDevmodeFields(&pUiData->ci, FALSE); // // Separate the doc-sticky options from the combined array // and save it back to the private devmode aOptions array // SeparateOptionArray( pci->pRawData, pci->pCombinedOptions, PGetDevmodeOptionsArray(pci->pdm), MAX_PRINTER_OPTIONS, MODE_DOCUMENT_STICKY); } BConvertDevmodeOut(pci->pdm, pDPHdr->pdmIn, pDPHdr->pdmOut); } pPSUIInfo->Result = pSRInfo->Result; } lRet = 1; break; case PROPSHEETUI_REASON_DESTROY: // // Clean up // VFreeUiData(pUiData); lRet = 1; break; default: ERR(("Unknown reason in DrvDocumentPropertySheets\n")); return -1; } return lRet; } LONG LSimpleDocumentProperties( IN OUT PDOCUMENTPROPERTYHEADER pDPHdr ) /*++ Routine Description: Handle simple "Document Properties" where we don't need to display a dialog and therefore don't have to have common UI library involved Mainly, devmode handling - update, merge, copy etc. Arguments: pDPHdr - Points to a DOCUMENTPROPERTYHEADER structure Return Value: > 0 if successful, <= 0 otherwise --*/ { PCOMMONINFO pci; DWORD dwSize; PPRINTER_INFO_2 pPrinterInfo2; // // Load common printer info // pci = PLoadCommonInfo(pDPHdr->hPrinter, pDPHdr->pszPrinterName, 0); if (!pci || !BCalcTotalOEMDMSize(pci->hPrinter, pci->pOemPlugins, &dwSize)) { VFreeCommonInfo(pci); return -1; } // // Check if the caller is interested in the size only // pDPHdr->cbOut = sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra + dwSize; if (pDPHdr->fMode == 0 || pDPHdr->pdmOut == NULL) { VFreeCommonInfo(pci); return pDPHdr->cbOut; } // // Merge the input devmode with the driver and system default devmodes // if (! (pPrinterInfo2 = MyGetPrinter(pci->hPrinter, 2)) || ! BFillCommonInfoDevmode(pci, pPrinterInfo2->pDevMode, pDPHdr->pdmIn)) { MemFree(pPrinterInfo2); VFreeCommonInfo(pci); return -1; } MemFree(pPrinterInfo2); // // Copy the devmode back into the output buffer provided by the caller // Always return the smaller of current and input devmode // if (pDPHdr->fMode & (DM_COPY | DM_UPDATE)) (VOID) BConvertDevmodeOut(pci->pdm, pDPHdr->pdmIn, pDPHdr->pdmOut); // // Clean up before returning to caller // VFreeCommonInfo(pci); return 1; } VOID VRestoreDefaultFeatureSelection( IN OUT PUIDATA pUiData ) /*++ Routine Description: Restore the printer feature selections to their default state Arguments: pUiData - Points to our UIDATA structure Return Value: NONE --*/ { POPTSELECT pOptionsArray; PFEATURE pFeature; POPTITEM pOptItem; DWORD dwCount, dwFeatureIndex, dwDefault; PUIINFO pUIInfo; // // Go through each printer feature item and check to see if // its current selection matches the default value // pUIInfo = pUiData->ci.pUIInfo; pOptionsArray = pUiData->ci.pCombinedOptions; pOptItem = pUiData->pFeatureItems; dwCount = pUiData->dwFeatureItem; for ( ; dwCount--; pOptItem++) { pFeature = (PFEATURE) GETUSERDATAITEM(pOptItem->UserData); dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature); dwDefault = pFeature->dwDefaultOptIndex; // // If the current selection doesn't match the default, // restore it to the default value. // if (pOptionsArray[dwFeatureIndex].ubCurOptIndex != dwDefault) { pOptionsArray[dwFeatureIndex].ubCurOptIndex = (BYTE) dwDefault; pOptItem->Flags |= OPTIF_CHANGED; pOptItem->Sel = (dwDefault == OPTION_INDEX_ANY) ? 0 : dwDefault; } } // // Update the display and indicate which items are constrained // VPropShowConstraints(pUiData, MODE_DOCANDPRINTER_STICKY); } VOID VOptionsToDevmodeFields( IN OUT PCOMMONINFO pci, IN BOOL bUpdateFormFields ) /*++ Routine Description: Convert options in pUiData->pOptionsArray into public devmode fields Arguments: pci - Points to basic printer info bUpdateFormFields - Whether or not to convert paper size option into devmode Return Value: None --*/ { PFEATURE pFeature; POPTION pOption; DWORD dwGID, dwFeatureIndex, dwOptionIndex; PUIINFO pUIInfo; PDEVMODE pdm; // // Go through all predefine IDs and propage the option selection // into appropriate devmode fields // pUIInfo = pci->pUIInfo; pdm = pci->pdm; for (dwGID=0 ; dwGID < MAX_GID ; dwGID++) { // // Get the feature to get the options, and get the index // into the option array // if ((pFeature = GET_PREDEFINED_FEATURE(pUIInfo, dwGID)) == NULL) continue; dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature); dwOptionIndex = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex; // // Get the pointer to the option array for the feature // if ((pOption = PGetIndexedOption(pUIInfo, pFeature, dwOptionIndex)) == NULL) continue; switch(dwGID) { case GID_RESOLUTION: { PRESOLUTION pRes = (PRESOLUTION)pOption; // // Get to the option selected // pdm->dmFields |= (DM_PRINTQUALITY|DM_YRESOLUTION); pdm->dmPrintQuality = GETQUALITY_X(pRes); pdm->dmYResolution = GETQUALITY_Y(pRes); } break; case GID_DUPLEX: // // Get to the option selected // pdm->dmFields |= DM_DUPLEX; pdm->dmDuplex = (SHORT) ((PDUPLEX) pOption)->dwDuplexID; break; case GID_INPUTSLOT: // // Get to the option selected // pdm->dmFields |= DM_DEFAULTSOURCE; pdm->dmDefaultSource = (SHORT) ((PINPUTSLOT) pOption)->dwPaperSourceID; break; case GID_MEDIATYPE: // // Get to the option selected // pdm->dmFields |= DM_MEDIATYPE; pdm->dmMediaType = (SHORT) ((PMEDIATYPE) pOption)->dwMediaTypeID; break; case GID_ORIENTATION: if (((PORIENTATION) pOption)->dwRotationAngle == ROTATE_NONE) pdm->dmOrientation = DMORIENT_PORTRAIT; else pdm->dmOrientation = DMORIENT_LANDSCAPE; pdm->dmFields |= DM_ORIENTATION; break; // // Fix #2822: VOptionsToDevmodeFields should be called after calling // VFixOptionsArrayWithDevmode and ResolveUIConflicts, which could // change option array to be out of sync with devmode. // case GID_COLLATE: pdm->dmFields |= DM_COLLATE; pdm->dmCollate = (SHORT) ((PCOLLATE) pOption)->dwCollateID; break; case GID_PAGESIZE: { PPAGESIZE pPageSize = (PPAGESIZE)pOption; WCHAR awchBuf[CCHPAPERNAME]; // // Ignore the custom page size option. We don't add custom page size option to the // form database, see BAddOrUpgradePrinterForms(). Also see BQueryPrintForm() for // special handling of custom page size for DDI DevQueryPrintEx(). // if (pPageSize->dwPaperSizeID == DMPAPER_USER || pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE) { VERBOSE(("VOptionsToDevmodeFields: %d ignored\n", pPageSize->dwPaperSizeID)); break; } // // bUpdateFormFields should be FALSE if we don't want to overwrite devmode form // fields with our option array's page size setting. One case of this is when // user hits the doc-setting UI's OK buttion, at that time we need to propagate // our internal devmode to app's output devmode. See cpcbDocumentPropertyCallback(). // That's because in option array we could have already mapped devmode's form request // to a paper size the printer supports (example: devmode requets Legal, we map // it to the printer's form OEM_Legal). So we don't want to overwrite output devmode // form fields with our internal option. // if (!bUpdateFormFields) break; if (!LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, awchBuf, CCHPAPERNAME)) { ERR(("VOptionsToDevmodeFields: cannot get paper name\n")); break; } pdm->dmFields &= ~(DM_PAPERWIDTH|DM_PAPERLENGTH|DM_PAPERSIZE); pdm->dmFields |= DM_FORMNAME; CopyString(pdm->dmFormName, awchBuf, CCHFORMNAME); if (!BValidateDevmodeFormFields( pci->hPrinter, pdm, NULL, pci->pSplForms, pci->dwSplForms)) { VDefaultDevmodeFormFields(pUIInfo, pdm, IsMetricCountry()); } } break; } } } CPSUICALLBACK cpcbDocumentPropertyCallback( IN OUT PCPSUICBPARAM pCallbackParam ) /*++ Routine Description: Callback function provided to common UI DLL for handling document properties dialog. Arguments: pCallbackParam - Pointer to CPSUICBPARAM structure Return Value: CPSUICB_ACTION_NONE - no action needed CPSUICB_ACTION_OPTIF_CHANGED - items changed and should be refreshed --*/ { PUIDATA pUiData; POPTITEM pCurItem, pOptItem; LONG lRet; PFEATURE pFeature; pUiData = (PUIDATA) pCallbackParam->UserData; ASSERT(pUiData != NULL); pUiData->hDlg = pCallbackParam->hDlg; pCurItem = pCallbackParam->pCurItem; lRet = CPSUICB_ACTION_NONE; // // If user has no permission to change anything, then // simply return without taking any action. // if (!HASPERMISSION(pUiData) && (pCallbackParam->Reason != CPSUICB_REASON_ABOUT)) return lRet; switch (pCallbackParam->Reason) { case CPSUICB_REASON_SEL_CHANGED: case CPSUICB_REASON_ECB_CHANGED: if (! IS_DRIVER_OPTITEM(pUiData, pCurItem)) break; // // Everytime the user make any changes, we update the // pOptionsArray. These settings are not saved to the devmode // until the user hit OK. // // VUnpackDocumentPropertiesItems saves the settings to pUiData->pOptionsArray // and update the private devmode flags if applicable. // ICheckConstraintsDlg check if the user has selected a constrained option // VUnpackDocumentPropertiesItems(pUiData, pCurItem, 1); #ifdef UNIDRV VSyncColorInformation(pUiData, pCurItem); // // Quality Macro support // if (GETUSERDATAITEM(pCurItem->UserData) == QUALITY_SETTINGS_ITEM || GETUSERDATAITEM(pCurItem->UserData) == COLOR_ITEM || GETUSERDATAITEM(pCurItem->UserData) == MEDIATYPE_ITEM || ((pFeature = PGetFeatureFromItem(pUiData->ci.pUIInfo, pCurItem, NULL))&& pFeature->dwFlags & FEATURE_FLAG_UPDATESNAPSHOT)) { VMakeMacroSelections(pUiData, pCurItem); // // Needs to update the constraints since Macro selection might have // changed the constraints // VPropShowConstraints(pUiData, MODE_DOCANDPRINTER_STICKY); VUpdateMacroSelection(pUiData, pCurItem); } else { // // Check whether the current selection invalidates the macros // and update QUALITY_SETTINGS_ITEM. VUpdateMacroSelection(pUiData, pCurItem); } #endif // UNIDRV #ifdef PSCRIPT if (GETUSERDATAITEM(pCurItem->UserData) == REVPRINT_ITEM) { VSyncRevPrintAndOutputOrder(pUiData, pCurItem); } #endif // PSCRIPT if (GETUSERDATAITEM(pCurItem->UserData) == METASPOOL_ITEM || GETUSERDATAITEM(pCurItem->UserData) == NUP_ITEM || GETUSERDATAITEM(pCurItem->UserData) == REVPRINT_ITEM || GETUSERDATAITEM(pCurItem->UserData) == COPIES_COLLATE_ITEM || ((pFeature = PGetFeatureFromItem(pUiData->ci.pUIInfo, pCurItem, NULL)) && pFeature->dwFeatureID == GID_OUTPUTBIN)) { VUpdateEmfFeatureItems(pUiData, GETUSERDATAITEM(pCurItem->UserData) != METASPOOL_ITEM); } #ifdef UNIDRV VSyncColorInformation(pUiData, pCurItem); #endif #ifdef PSCRIPT // // If the user has selected custom page size, // bring up the custom page size dialog now. // if (GETUSERDATAITEM(pCurItem->UserData) == FORMNAME_ITEM && pCurItem->pExtPush != NULL) { if (pUiData->pwPapers[pCurItem->Sel] == DMPAPER_CUSTOMSIZE) { (VOID) BDisplayPSCustomPageSizeDialog(pUiData); pCurItem->Flags &= ~(OPTIF_EXT_HIDE | OPTIF_EXT_DISABLED); } else pCurItem->Flags |= (OPTIF_EXT_HIDE | OPTIF_EXT_DISABLED); pCurItem->Flags |= OPTIF_CHANGED; } #endif // PSCRIPT // // Update the display and indicate which items are constrained. // VPropShowConstraints(pUiData, MODE_DOCANDPRINTER_STICKY); lRet = CPSUICB_ACTION_REINIT_ITEMS; break; case CPSUICB_REASON_ITEMS_REVERTED: // // Unpack document properties treeview items // VUnpackDocumentPropertiesItems(pUiData, pUiData->pDrvOptItem, pUiData->dwDrvOptItem); // // Update the display and indicate which items are constrained // VPropShowConstraints(pUiData, MODE_DOCANDPRINTER_STICKY); lRet = CPSUICB_ACTION_OPTIF_CHANGED; break; case CPSUICB_REASON_EXTPUSH: #ifdef PSCRIPT if (GETUSERDATAITEM(pCurItem->UserData) == FORMNAME_ITEM) { // // Push button to bring up PostScript custom page size dialog // (VOID) BDisplayPSCustomPageSizeDialog(pUiData); } #endif // PSCRIPT if (pCurItem == pUiData->pFeatureHdrItem) { // // Push button for restoring all generic feature selections // to their default values // VRestoreDefaultFeatureSelection(pUiData); lRet = CPSUICB_ACTION_REINIT_ITEMS; } break; case CPSUICB_REASON_ABOUT: DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_ABOUT), pUiData->hDlg, (DLGPROC) _AboutDlgProc, (LPARAM) pUiData); break; case CPSUICB_REASON_APPLYNOW: pUiData->ci.dwFlags |= FLAG_APPLYNOW_CALLED; // // Check if there are still any unresolved constraints left? // BOptItemSelectionsChanged returns TRUE or FALSE depending on // whether the user has made any changes to the options // if (((pUiData->ci.dwFlags & FLAG_PLUGIN_CHANGED_OPTITEM) || BOptItemSelectionsChanged(pUiData->pDrvOptItem, pUiData->dwDrvOptItem)) && ICheckConstraintsDlg(pUiData, pUiData->pDrvOptItem, pUiData->dwDrvOptItem, TRUE) == CONFLICT_CANCEL) { // // Conflicts found and user clicked CANCEL to // go back to the dialog without dismissing it. // lRet = CPSUICB_ACTION_NO_APPLY_EXIT; break; } // // Transfer information from options array to public devmode fields // VOptionsToDevmodeFields(&pUiData->ci, FALSE); // // Separate the doc-sticky options from the combined array // and save it back to the private devmode aOptions array // SeparateOptionArray( pUiData->ci.pRawData, pUiData->ci.pCombinedOptions, PGetDevmodeOptionsArray(pUiData->ci.pdm), MAX_PRINTER_OPTIONS, MODE_DOCUMENT_STICKY); pCallbackParam->Result = CPSUI_OK; lRet = CPSUICB_ACTION_ITEMS_APPLIED ; break; } return LInvokeOemPluginCallbacks(pUiData, pCallbackParam, lRet); } BOOL BPackItemFormName( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack Paper size options. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { // // Extended push button for bringing up PostScript custom page size dialog // PFEATURE pFeature; static EXTPUSH ExtPush = { sizeof(EXTPUSH), EPF_NO_DOT_DOT_DOT, (PWSTR) IDS_EDIT_CUSTOMSIZE, NULL, 0, 0, }; if (!(pFeature = GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_PAGESIZE)) || pFeature->Options.dwCount < MIN_OPTIONS_ALLOWED || pFeature->dwFlags & FEATURE_FLAG_NOUI) return TRUE; if (pUiData->pOptItem) { DWORD dwFormNames, dwIndex, dwSel, dwPageSizeIndex, dwOption; PWSTR pFormNames; POPTPARAM pOptParam; PUIINFO pUIInfo = pUiData->ci.pUIInfo; PFEATURE pPageSizeFeature; BOOL bSupported; dwFormNames = pUiData->dwFormNames; pFormNames = pUiData->pFormNames; // // Figure out the currently selected paper size option index // dwSel = DwFindFormNameIndex(pUiData, pUiData->ci.pdm->dmFormName, &bSupported); // // If the form is not supported on the printer, it could be the case // where the printer doesn't support a form with the same name, but // the printer can still support the requested form using exact or // closest paper size match. // // See function VFixOptionsArrayWithDevmode() and ChangeOptionsViaID(). // if (!bSupported && (pPageSizeFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_PAGESIZE))) { WCHAR awchBuf[CCHPAPERNAME]; PPAGESIZE pPageSize; // // If we can't find a name match in the first DwFindFormNameIndex call, // the option array should already have the correct option index value // parser has decided to use to support the form. So now we only need // to load the option's display name and search in the form name list // again to get the paper size UI list index. // dwPageSizeIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pPageSizeFeature); dwOption = pUiData->ci.pCombinedOptions[dwPageSizeIndex].ubCurOptIndex; if ((pPageSize = (PPAGESIZE)PGetIndexedOption(pUIInfo, pPageSizeFeature, dwOption)) && LOAD_STRING_PAGESIZE_NAME(&(pUiData->ci), pPageSize, awchBuf, CCHPAPERNAME)) { dwSel = DwFindFormNameIndex(pUiData, awchBuf, NULL); } } // // Fill out OPTITEM, OPTTYPE, and OPTPARAM structures // FILLOPTITEM(pUiData->pOptItem, pUiData->pOptType, ULongToPtr(IDS_CPSUI_FORMNAME), ULongToPtr(dwSel), TVITEM_LEVEL1, DMPUB_FORMNAME, FORMNAME_ITEM, HELP_INDEX_FORMNAME); pUiData->pOptType->Style = OTS_LBCB_SORT; pOptParam = PFillOutOptType(pUiData->pOptType, TVOT_LISTBOX, dwFormNames, pUiData->ci.hHeap); if (pOptParam == NULL) return FALSE; for (dwIndex=0; dwIndex < dwFormNames; dwIndex++) { pOptParam->cbSize = sizeof(OPTPARAM); pOptParam->pData = pFormNames; if (pUiData->pwPapers[dwIndex] == DMPAPER_CUSTOMSIZE) pOptParam->IconID = IDI_CUSTOM_PAGESIZE; else if (pOptParam->IconID = HLoadFormIconResource(pUiData, dwIndex)) pOptParam->Flags |= OPTPF_ICONID_AS_HICON; else pOptParam->IconID = DwGuessFormIconID(pFormNames); pOptParam++; pFormNames += CCHPAPERNAME; } // // Special case for PostScript custom page size // #ifdef PSCRIPT { PPPDDATA pPpdData; pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pUiData->ci.pRawData); ASSERT(pPpdData != NULL); if (SUPPORT_CUSTOMSIZE(pUIInfo) && SUPPORT_FULL_CUSTOMSIZE_FEATURES(pUIInfo, pPpdData)) { pUiData->pOptItem->Flags |= (OPTIF_EXT_IS_EXTPUSH|OPTIF_CALLBACK); pUiData->pOptItem->pExtPush = &ExtPush; // // If PostScript custom page size is selected, // select the last item of form name list. // if (pUiData->ci.pdm->dmPaperSize == DMPAPER_CUSTOMSIZE) { pUiData->pOptItem->Sel = pUiData->dwFormNames - 1; pUiData->pOptItem->Flags &= ~(OPTIF_EXT_HIDE | OPTIF_EXT_DISABLED); } else pUiData->pOptItem->Flags |= (OPTIF_EXT_HIDE | OPTIF_EXT_DISABLED); } } #endif // PSCRIPT #ifdef UNIDRV // // Supports OEM help file. If helpfile and helpindex are defined, // we will use the help id specified by the GPD. According to GPD spec, // zero loHelpFileName means no help file name specified. // if (pUIInfo->loHelpFileName && pFeature->iHelpIndex != UNUSED_ITEM) { POIEXT pOIExt = HEAPALLOC(pUiData->ci.hHeap, sizeof(OIEXT)); if (pOIExt) { pOIExt->cbSize = sizeof(OIEXT); pOIExt->Flags = 0; pOIExt->hInstCaller = NULL; pOIExt->pHelpFile = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pUIInfo->loHelpFileName); pUiData->pOptItem->pOIExt = pOIExt; pUiData->pOptItem->HelpIndex = pFeature->iHelpIndex; pUiData->pOptItem->Flags |= OPTIF_HAS_POIEXT; } } #endif // UNIDRV // // Set the Keyword name for pOptItem->UserData // SETUSERDATA_KEYWORDNAME(pUiData->ci, pUiData->pOptItem, pFeature); pUiData->pOptItem++; pUiData->pOptType++; } pUiData->dwOptItem++; pUiData->dwOptType++; return TRUE; } BOOL BPackItemInputSlot( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack paper source option. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { POPTTYPE pOptType; PFEATURE pFeature; PINPUTSLOT pInputSlot; pFeature = GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_INPUTSLOT); pOptType = pUiData->pOptType; if (! BPackItemPrinterFeature( pUiData, pFeature, TVITEM_LEVEL1, DMPUB_DEFSOURCE, (ULONG_PTR)INPUTSLOT_ITEM, HELP_INDEX_INPUT_SLOT)) { return FALSE; } // // NOTE: if the first input slot has dwPaperSourceID == DMBIN_FORMSOURCE, // then we'll change its display name to "Automatically Select". // if (pOptType != NULL && pOptType != pUiData->pOptType) { ASSERT(pFeature != NULL); pInputSlot = PGetIndexedOption(pUiData->ci.pUIInfo, pFeature, 0); ASSERT(pInputSlot != NULL); if (pInputSlot->dwPaperSourceID == DMBIN_FORMSOURCE) pOptType->pOptParam[0].pData = (PWSTR) IDS_TRAY_FORMSOURCE; } return TRUE; } BOOL BPackItemMediaType( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack media type option. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { return BPackItemPrinterFeature( pUiData, GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_MEDIATYPE), TVITEM_LEVEL1, DMPUB_MEDIATYPE, (ULONG_PTR)MEDIATYPE_ITEM, HELP_INDEX_MEDIA_TYPE); } static CONST WORD CopiesCollateItemInfo[] = { IDS_CPSUI_COPIES, TVITEM_LEVEL1, DMPUB_COPIES_COLLATE, COPIES_COLLATE_ITEM, HELP_INDEX_COPIES_COLLATE, 2, TVOT_UDARROW, 0, IDI_CPSUI_COPY, 0, MIN_COPIES, ITEM_INFO_SIGNATURE }; BOOL BPackItemCopiesCollate( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack copies and collate option. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { POPTITEM pOptItem = pUiData->pOptItem; PEXTCHKBOX pExtCheckbox; PFEATURE pFeature; SHORT sCopies, sMaxCopies; if ((pFeature = GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_COLLATE)) && pFeature->dwFlags & FEATURE_FLAG_NOUI) return TRUE; if (pUiData->bEMFSpooling) { sCopies = pUiData->ci.pdm->dmCopies; sMaxCopies = max(MAX_COPIES, (SHORT)pUiData->ci.pUIInfo->dwMaxCopies); } else { sCopies = pUiData->ci.pdm->dmCopies > (SHORT)pUiData->ci.pUIInfo->dwMaxCopies ? (SHORT)pUiData->ci.pUIInfo->dwMaxCopies : pUiData->ci.pdm->dmCopies; sMaxCopies = (SHORT)pUiData->ci.pUIInfo->dwMaxCopies; } if (! BPackUDArrowItemTemplate( pUiData, CopiesCollateItemInfo, sCopies, sMaxCopies, pFeature)) { return FALSE; } if (pOptItem && DRIVER_SUPPORTS_COLLATE(((PCOMMONINFO)&pUiData->ci))) { pExtCheckbox = HEAPALLOC(pUiData->ci.hHeap, sizeof(EXTCHKBOX)); if (pExtCheckbox == NULL) { ERR(("Memory allocation failed\n")); return FALSE; } pExtCheckbox->cbSize = sizeof(EXTCHKBOX); pExtCheckbox->pTitle = (PWSTR) IDS_CPSUI_COLLATE; pExtCheckbox->pCheckedName = (PWSTR) IDS_CPSUI_COLLATED; pExtCheckbox->IconID = IDI_CPSUI_COLLATE; pExtCheckbox->Flags = ECBF_CHECKNAME_ONLY_ENABLED; pExtCheckbox->pSeparator = (PWSTR)IDS_CPSUI_SLASH_SEP; pOptItem->pExtChkBox = pExtCheckbox; if ((pUiData->ci.pdm->dmFields & DM_COLLATE) && (pUiData->ci.pdm->dmCollate == DMCOLLATE_TRUE)) { pOptItem->Flags |= OPTIF_ECB_CHECKED; } } return TRUE; } BOOL BPackItemResolution( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack resolution option. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { return BPackItemPrinterFeature( pUiData, GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_RESOLUTION), TVITEM_LEVEL1, DMPUB_PRINTQUALITY, (ULONG_PTR)RESOLUTION_ITEM, HELP_INDEX_RESOLUTION); } static CONST WORD ColorItemInfo[] = { IDS_CPSUI_COLOR, TVITEM_LEVEL1, DMPUB_COLOR, COLOR_ITEM, HELP_INDEX_COLOR, 2, TVOT_2STATES, IDS_CPSUI_MONOCHROME, IDI_CPSUI_MONO, IDS_CPSUI_COLOR, IDI_CPSUI_COLOR, ITEM_INFO_SIGNATURE }; // // ICM stuff is not available on NT4 // #ifndef WINNT_40 static CONST WORD ICMMethodItemInfo[] = { IDS_ICMMETHOD, TVITEM_LEVEL1, #ifdef WINNT_40 DMPUB_NONE, #else DMPUB_ICMMETHOD, #endif ICMMETHOD_ITEM, HELP_INDEX_ICMMETHOD, #ifdef PSCRIPT 4, TVOT_LISTBOX, #else 3, TVOT_LISTBOX, #endif IDS_ICMMETHOD_NONE, IDI_ICMMETHOD_NONE, IDS_ICMMETHOD_SYSTEM, IDI_ICMMETHOD_SYSTEM, IDS_ICMMETHOD_DRIVER, IDI_ICMMETHOD_DRIVER, #ifdef PSCRIPT IDS_ICMMETHOD_DEVICE, IDI_ICMMETHOD_DEVICE, #endif ITEM_INFO_SIGNATURE }; static CONST WORD ICMIntentItemInfo[] = { IDS_ICMINTENT, TVITEM_LEVEL1, #ifdef WINNT_40 DMPUB_NONE, #else DMPUB_ICMINTENT, #endif ICMINTENT_ITEM, HELP_INDEX_ICMINTENT, 4, TVOT_LISTBOX, IDS_ICMINTENT_SATURATE, IDI_ICMINTENT_SATURATE, IDS_ICMINTENT_CONTRAST, IDI_ICMINTENT_CONTRAST, IDS_ICMINTENT_COLORIMETRIC, IDI_ICMINTENT_COLORIMETRIC, IDS_ICMINTENT_ABS_COLORIMETRIC, IDI_ICMINTENT_ABS_COLORIMETRIC, ITEM_INFO_SIGNATURE }; #endif // !WINNT_40 BOOL BPackItemColor( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack color mode option. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { PDEVMODE pdm; INT dwColorSel, dwICMMethodSel, dwICMIntentSel; // // For Adobe driver, they want to preserve the color information // even for b/w printers. So we always give user this choice. // #ifndef ADOBE if (! IS_COLOR_DEVICE(pUiData->ci.pUIInfo)) return TRUE; #endif // !ADOBE // // DCR - Some ICM methods and intents may need to be disabled // on some non-PostScript printers. // pdm = pUiData->ci.pdm; dwColorSel = dwICMMethodSel = dwICMIntentSel = 0; if ((pdm->dmFields & DM_COLOR) && (pdm->dmColor == DMCOLOR_COLOR)) dwColorSel = 1; if (! BPackOptItemTemplate(pUiData, ColorItemInfo, dwColorSel, NULL)) return FALSE; // // ICM stuff is not available on NT4 // #ifndef WINNT_40 if (pdm->dmFields & DM_ICMMETHOD) { switch (pdm->dmICMMethod) { case DMICMMETHOD_SYSTEM: dwICMMethodSel = 1; break; case DMICMMETHOD_DRIVER: dwICMMethodSel = 2; break; #ifdef PSCRIPT case DMICMMETHOD_DEVICE: dwICMMethodSel = 3; break; #endif case DMICMMETHOD_NONE: default: dwICMMethodSel = 0; break; } } if (pdm->dmFields & DM_ICMINTENT) { switch (pdm->dmICMIntent) { case DMICM_COLORIMETRIC: dwICMIntentSel = 2; break; case DMICM_ABS_COLORIMETRIC: dwICMIntentSel = 3; break; case DMICM_SATURATE: dwICMIntentSel = 0; break; case DMICM_CONTRAST: default: dwICMIntentSel = 1; break; } } if (! BPackOptItemTemplate(pUiData, ICMMethodItemInfo, dwICMMethodSel, NULL) || ! BPackOptItemTemplate(pUiData, ICMIntentItemInfo, dwICMIntentSel, NULL)) { return FALSE; } #endif // !WINNT_40 return TRUE; } BOOL BPackItemDuplex( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack duplexing option. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { POPTITEM pOptItem = pUiData->pOptItem; PCOMMONINFO pci = &pUiData->ci; PFEATURE pFeature = GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_DUPLEX); BOOL bRet; // // Don't display the duplex feature if duplex is constrained by an // installable feature such as duplex unit not installed // if (!SUPPORTS_DUPLEX(pci) || (pFeature && pFeature->Options.dwCount < MIN_OPTIONS_ALLOWED)) return TRUE; bRet = BPackItemPrinterFeature( pUiData, pFeature, TVITEM_LEVEL1, DMPUB_DUPLEX, (ULONG_PTR)DUPLEX_ITEM, HELP_INDEX_DUPLEX); #ifdef WINNT_40 // // Use standard names for duplex options. Otherwise, the duplex option // names from the PPD/GPD file may be too long to fit into the space // on the friendly (Page Setup) tab. // // On NT5, this kluge is inside compstui. // if (bRet && pFeature && pOptItem) { DWORD dwIndex; INT StrRsrcId; PDUPLEX pDuplex; for (dwIndex=0; dwIndex < pOptItem->pOptType->Count; dwIndex++) { pDuplex = (PDUPLEX) PGetIndexedOption(pUiData->ci.pUIInfo, pFeature, dwIndex); ASSERT(pDuplex != NULL); switch (pDuplex->dwDuplexID) { case DMDUP_HORIZONTAL: StrRsrcId = IDS_CPSUI_SHORT_SIDE; break; case DMDUP_VERTICAL: StrRsrcId = IDS_CPSUI_LONG_SIDE; break; default: StrRsrcId = IDS_CPSUI_NONE; break; } pOptItem->pOptType->pOptParam[dwIndex].pData = (PWSTR) StrRsrcId; } } #endif // WINNT_40 return bRet; } static CONST WORD TTOptionItemInfo[] = { IDS_CPSUI_TTOPTION, TVITEM_LEVEL1, DMPUB_TTOPTION, TTOPTION_ITEM, HELP_INDEX_TTOPTION, 2, TVOT_2STATES, IDS_CPSUI_TT_SUBDEV, IDI_CPSUI_TT_SUBDEV, IDS_CPSUI_TT_DOWNLOADSOFT, IDI_CPSUI_TT_DOWNLOADSOFT, ITEM_INFO_SIGNATURE }; BOOL BPackItemTTOptions( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack TT options Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { DWORD dwSel; // // If device fonts have been disabled or doesn't support // font substitution , then don't // show font substitution option // if (pUiData->ci.pPrinterData->dwFlags & PFLAGS_IGNORE_DEVFONT || pUiData->ci.pUIInfo->dwFontSubCount == 0 ) { pUiData->ci.pdm->dmTTOption = DMTT_DOWNLOAD; return TRUE; } dwSel = (pUiData->ci.pdm->dmTTOption == DMTT_SUBDEV) ? 0 : 1; return BPackOptItemTemplate(pUiData, TTOptionItemInfo, dwSel, NULL); } static CONST WORD ItemInfoMFSpool[] = { IDS_METAFILE_SPOOLING, TVITEM_LEVEL1, DMPUB_NONE, METASPOOL_ITEM, HELP_INDEX_METAFILE_SPOOLING, 2, TVOT_2STATES, IDS_ENABLED, IDI_CPSUI_ON, IDS_DISABLED, IDI_CPSUI_OFF, ITEM_INFO_SIGNATURE }; static CONST WORD ItemInfoNupOption[] = { IDS_NUPOPTION, TVITEM_LEVEL1, NUP_DMPUB, NUP_ITEM, HELP_INDEX_NUPOPTION, 7, TVOT_LISTBOX, IDS_ONE_UP, IDI_ONE_UP, IDS_TWO_UP, IDI_TWO_UP, IDS_FOUR_UP, IDI_FOUR_UP, IDS_SIX_UP, IDI_SIX_UP, IDS_NINE_UP, IDI_NINE_UP, IDS_SIXTEEN_UP, IDI_SIXTEEN_UP, IDS_BOOKLET , IDI_BOOKLET, ITEM_INFO_SIGNATURE }; static CONST WORD ItemInfoRevPrint[] = { IDS_PAGEORDER, TVITEM_LEVEL1, PAGEORDER_DMPUB, REVPRINT_ITEM, HELP_INDEX_REVPRINT, 2, TVOT_2STATES, IDS_PAGEORDER_NORMAL, IDI_PAGEORDER_NORMAL, IDS_PAGEORDER_REVERSE, IDI_PAGEORDER_REVERSE, ITEM_INFO_SIGNATURE }; BOOL BPackItemEmfFeatures( PUIDATA pUiData ) /*++ Routine Description: Pack EMF related feature items: EMF spooling on/off N-up reverse-order printing Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { PDRIVEREXTRA pdmExtra = pUiData->ci.pdmPrivate; BOOL bNupOption, bReversePrint; PCOMMONINFO pci = &pUiData->ci; DWORD dwSel; POPTITEM pOptItem; // // Check if the spooler can do N-up and reverse-order printing // for the current printer // VGetSpoolerEmfCaps(pci->hPrinter, &bNupOption, &bReversePrint, 0, NULL); // // On Win2K and above, don't show the EMF spooling option in driver UI // if spooler cannot do EMF. // pUiData->bEMFSpooling is initialized at PFillUidata // 1. Determine if Reverse Print is possible // 2. Spooler can do EMF. // // On NT4, since spooler doesn't support the EMF capability query, we // have to keep the old NT4 driver behavior of always showing the EMF // spooling option in driver UI. // #ifndef WINNT_40 if (pUiData->bEMFSpooling) { #endif dwSel = ISSET_MFSPOOL_FLAG(pdmExtra) ? 0 : 1; if (!BPackOptItemTemplate(pUiData, ItemInfoMFSpool, dwSel, NULL)) return FALSE; #ifndef WINNT_40 } #endif #ifdef PSCRIPT bNupOption = TRUE; #endif // // Pack N-up option item if necessary // if (bNupOption) { switch (NUPOPTION(pdmExtra)) { case TWO_UP: dwSel = 1; break; case FOUR_UP: dwSel = 2; break; case SIX_UP: dwSel = 3; break; case NINE_UP: dwSel = 4; break; case SIXTEEN_UP: dwSel = 5; break; case BOOKLET_UP: dwSel = 6; break; case ONE_UP: default: dwSel = 0; break; } pOptItem = pUiData->pOptItem; if (!BPackOptItemTemplate(pUiData, ItemInfoNupOption, dwSel, NULL)) return FALSE; // // Hide booklet option if duplex is constrained by an // installable feature such as duplex unit not installed or EMF is not // available. // if ( pOptItem && (!pUiData->bEMFSpooling || !SUPPORTS_DUPLEX(pci))) { pOptItem->pOptType->pOptParam[BOOKLET_UP].Flags |= OPTPF_HIDE; if (NUPOPTION(pdmExtra) == BOOKLET_UP) pOptItem->Sel = 1; } } else { NUPOPTION(pdmExtra) = ONE_UP; } // // Pack Reverse-order printing option item if necessary // if (bReversePrint) { dwSel = REVPRINTOPTION(pdmExtra) ? 1 : 0; if (!BPackOptItemTemplate(pUiData, ItemInfoRevPrint, dwSel, NULL)) return FALSE; } else { REVPRINTOPTION(pdmExtra) = FALSE; } if (pUiData->bEMFSpooling && pUiData->pOptItem) VUpdateEmfFeatureItems(pUiData, FALSE); return TRUE; } BOOL BPackDocumentPropertyItems( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack document property information into treeview items. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { return BPackItemFormName(pUiData) && BPackItemInputSlot(pUiData) && _BPackOrientationItem(pUiData) && BPackItemCopiesCollate(pUiData) && BPackItemResolution(pUiData) && BPackItemColor(pUiData) && _BPackItemScale(pUiData) && BPackItemDuplex(pUiData) && BPackItemMediaType(pUiData) && BPackItemTTOptions(pUiData) && BPackItemEmfFeatures(pUiData) && _BPackDocumentOptions(pUiData) && BPackItemGenericOptions(pUiData) && BPackOemPluginItems(pUiData); } VOID VUnpackDocumentPropertiesItems( PUIDATA pUiData, POPTITEM pOptItem, DWORD dwOptItem ) /*++ Routine Description: Extract devmode information from an OPTITEM Stored it back into devmode. Arguments: pUiData - Pointer to our UIDATA structure pOptItem - Pointer to an array of OPTITEMs dwOptItem - Number of OPTITEMs Return Value: Printer feature index corresponding to the last item unpacked --*/ { PUIINFO pUIInfo = pUiData->ci.pUIInfo; PDEVMODE pdm = pUiData->ci.pdm; PDRIVEREXTRA pdmExtra = pUiData->ci.pdmPrivate; for ( ; dwOptItem > 0; dwOptItem--, pOptItem++) { // // Header items always have pOptType == NULL, see // VPackOptItemGroupHeader // if (pOptItem->pOptType == NULL) continue; // // To fix bug #90923, we should only allow hidden items to be processed when we are within // the UI helper function call BUpdateUISettingForOEM issued by OEM plguin. // // We don't do this for other cases because there are already UI plugins that hide our // standard items and show their own. For example, CNBJUI.DLL hides our ICMMETHOD_ITEM // and ICMINTENT_ITEM. It uses its own as replacement items. If we change the behavior here, // we could break those plugins when we process the hidden items and overwrite the devmode // plugin has already set based on user selection of their replacement items. // if (!(pUiData->ci.dwFlags & FLAG_WITHIN_PLUGINCALL) && (pOptItem->Flags & OPTIF_HIDE)) continue; if (ISPRINTERFEATUREITEM(pOptItem->UserData)) { // // Generic document-sticky printer features // VUpdateOptionsArrayWithSelection(pUiData, pOptItem); } else { // // Common items in public devmode // switch (GETUSERDATAITEM(pOptItem->UserData)) { case ORIENTATION_ITEM: // // Orientation is a special case: // for pscript, it's handled via _VUnpackDocumentOptions // for unidrv, it's handled as a generic feature // #ifdef PSCRIPT break; #endif case DUPLEX_ITEM: VUpdateOptionsArrayWithSelection(pUiData, pOptItem); VUpdateBookletOption(pUiData, pOptItem); break; case RESOLUTION_ITEM: case INPUTSLOT_ITEM: case MEDIATYPE_ITEM: case COLORMODE_ITEM: case HALFTONING_ITEM: VUpdateOptionsArrayWithSelection(pUiData, pOptItem); break; case SCALE_ITEM: pdm->dmScale = (SHORT) pOptItem->Sel; break; case COPIES_COLLATE_ITEM: pdm->dmCopies = (SHORT) pOptItem->Sel; if (pOptItem->pExtChkBox) { pdm->dmFields |= DM_COLLATE; pdm->dmCollate = (pOptItem->Flags & OPTIF_ECB_CHECKED) ? DMCOLLATE_TRUE : DMCOLLATE_FALSE; // // Update Collate feature option index // ChangeOptionsViaID( pUiData->ci.pInfoHeader, pUiData->ci.pCombinedOptions, GID_COLLATE, pdm); } break; case COLOR_ITEM: pdm->dmFields |= DM_COLOR; pdm->dmColor = (pOptItem->Sel == 1) ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME; break; case METASPOOL_ITEM: if (pOptItem->Sel == 0) { SET_MFSPOOL_FLAG(pdmExtra); } else { CLEAR_MFSPOOL_FLAG(pdmExtra); } break; case NUP_ITEM: switch (pOptItem->Sel) { case 1: NUPOPTION(pdmExtra) = TWO_UP; break; case 2: NUPOPTION(pdmExtra) = FOUR_UP; break; case 3: NUPOPTION(pdmExtra) = SIX_UP; break; case 4: NUPOPTION(pdmExtra) = NINE_UP; break; case 5: NUPOPTION(pdmExtra) = SIXTEEN_UP; break; case 6: NUPOPTION(pdmExtra) = BOOKLET_UP; VUpdateBookletOption(pUiData, pOptItem); break; case 0: default: NUPOPTION(pdmExtra) = ONE_UP; break; } break; case REVPRINT_ITEM: REVPRINTOPTION(pdmExtra) = (pOptItem->Sel != 0); break; // // ICM stuff is not available on NT4 // #ifndef WINNT_40 case ICMMETHOD_ITEM: pdm->dmFields |= DM_ICMMETHOD; switch (pOptItem->Sel) { case 0: pdm->dmICMMethod = DMICMMETHOD_NONE; break; case 1: pdm->dmICMMethod = DMICMMETHOD_SYSTEM; break; case 2: pdm->dmICMMethod = DMICMMETHOD_DRIVER; break; #ifdef PSCRIPT case 3: pdm->dmICMMethod = DMICMMETHOD_DEVICE; break; #endif } break; case ICMINTENT_ITEM: pdm->dmFields |= DM_ICMINTENT; switch (pOptItem->Sel) { case 0: pdm->dmICMIntent = DMICM_SATURATE; break; case 1: pdm->dmICMIntent = DMICM_CONTRAST; break; case 2: pdm->dmICMIntent = DMICM_COLORIMETRIC; break; case 3: pdm->dmICMIntent = DMICM_ABS_COLORIMETRIC; break; } break; #endif // !WINNT_40 case TTOPTION_ITEM: pdm->dmFields |= DM_TTOPTION; if (pOptItem->Sel == 0) pdm->dmTTOption = DMTT_SUBDEV; else pdm->dmTTOption = DMTT_DOWNLOAD; break; case FORMNAME_ITEM: pdm->dmFields &= ~(DM_PAPERLENGTH|DM_PAPERWIDTH); pdm->dmFields |= DM_PAPERSIZE; pdm->dmPaperSize = pUiData->pwPapers[pOptItem->Sel]; if (pdm->dmPaperSize == DMPAPER_CUSTOMSIZE) pdm->dmFields &= ~DM_FORMNAME; else pdm->dmFields |= DM_FORMNAME; CopyString(pdm->dmFormName, pOptItem->pOptType->pOptParam[pOptItem->Sel].pData, CCHFORMNAME); // // Update PageSize feature option index // { INT dwIndex; if (PGetFeatureFromItem(pUiData->ci.pUIInfo, pOptItem, &dwIndex)) { pUiData->ci.pCombinedOptions[dwIndex].ubCurOptIndex = (BYTE) pUiData->pwPaperFeatures[pOptItem->Sel]; } } break; } // // Give drivers a chance to process their private items // _VUnpackDocumentOptions(pOptItem, pdm); } } } VOID VUpdateEmfFeatureItems( PUIDATA pUiData, BOOL bUpdateMFSpoolItem ) /*++ Routine Description: Handle the inter-dependency between EMF spooling, N-up, and reverse-printing items. Arguments: pUiData - Points to UIDATA structure bUpdateMFSpoolItem - Whether to update EMF spooling or the other two items Return Value: NONE --*/ { POPTITEM pMFSpoolItem, pNupItem, pRevPrintItem, pCopiesCollateItem; pMFSpoolItem = PFindOptItemWithUserData(pUiData, METASPOOL_ITEM); pNupItem = PFindOptItemWithUserData(pUiData, NUP_ITEM); pRevPrintItem = PFindOptItemWithUserData(pUiData, REVPRINT_ITEM); pCopiesCollateItem = PFindOptItemWithUserData(pUiData, COPIES_COLLATE_ITEM); if (pMFSpoolItem == NULL) return; if (bUpdateMFSpoolItem) { // // Force EMF spooling to be on if: // N-up option is not ONE_UP (Unidrv only), or // reverse-order printing is enabled or // collate is not supported by the device or // copies count is > than max count support by device // #ifdef UNIDRV if (pNupItem && pNupItem->Sel != 0) pMFSpoolItem->Sel = 0; #endif // UNIDRV if (pNupItem && pNupItem->Sel == BOOKLET_UP) pMFSpoolItem->Sel = 0; if (pRevPrintItem) { // // Turn on EMF if the user selects "Normal" and // the bin is "Reversed" OR user selects "Reversed" // and the bin is "Normal" // BOOL bReversed = BGetPageOrderFlag(&pUiData->ci); if ( pRevPrintItem->Sel == 0 && bReversed || pRevPrintItem->Sel != 0 && !bReversed ) pMFSpoolItem->Sel = 0; } if (pCopiesCollateItem) { if (((pCopiesCollateItem->Flags & OPTIF_ECB_CHECKED) && !PRINTER_SUPPORTS_COLLATE(((PCOMMONINFO)&pUiData->ci))) || (pCopiesCollateItem->Sel > (LONG)pUiData->ci.pUIInfo->dwMaxCopies)) { pMFSpoolItem->Sel = 0; } } pMFSpoolItem->Flags |= OPTIF_CHANGED; VUnpackDocumentPropertiesItems(pUiData, pMFSpoolItem, 1); } else { // // If EMF spooling is turned off, force: // N-up option to be ONE_UP (Unidrv only), and // collate to be off if the device doesn't support collation // copies set to the max count handle by the device // if (pMFSpoolItem->Sel != 0) { #ifdef UNIDRV if (pNupItem) { pNupItem->Sel = 0; pNupItem->Flags |= OPTIF_CHANGED; VUnpackDocumentPropertiesItems(pUiData, pNupItem, 1); } #endif // UNIDRV if (pNupItem && pNupItem->Sel == BOOKLET_UP) { pNupItem->Sel = 0; pNupItem->Flags |= OPTIF_CHANGED; VUnpackDocumentPropertiesItems(pUiData, pNupItem, 1); } if (pCopiesCollateItem) { if ((pCopiesCollateItem->Flags & OPTIF_ECB_CHECKED) && !PRINTER_SUPPORTS_COLLATE(((PCOMMONINFO)&pUiData->ci))) { pCopiesCollateItem->Flags &=~OPTIF_ECB_CHECKED; } if (pCopiesCollateItem->Sel > (LONG)pUiData->ci.pUIInfo->dwMaxCopies) pCopiesCollateItem->Sel = (LONG)pUiData->ci.pUIInfo->dwMaxCopies; pCopiesCollateItem->Flags |= OPTIF_CHANGED; VUnpackDocumentPropertiesItems(pUiData, pCopiesCollateItem, 1); } // // EMF is OFF. Need to make the "Page Order" option consistent // with the current output bin. If bin is "Reversed" and user selects // "Normal", change it to "Reverse". If bin is "Normal" and user selects // "Reverse", change it to "Normal" // if (pRevPrintItem) { BOOL bReversed = BGetPageOrderFlag(&pUiData->ci); if (pRevPrintItem->Sel == 0 && bReversed ) pRevPrintItem->Sel = 1; else if ( pRevPrintItem->Sel != 0 && !bReversed ) pRevPrintItem->Sel = 0; pRevPrintItem->Flags |= OPTIF_CHANGED; VUnpackDocumentPropertiesItems(pUiData, pRevPrintItem, 1); } } } } BOOL BGetPageOrderFlag( PCOMMONINFO pci ) /*++ Routine Description: Get the page order flag for the specified output bin Arguments: pci - Pointer to PCOMMONINFO Return Value: TRUE if output bin is reverse. otherwise, FALSE --*/ { PUIINFO pUIInfo = pci->pUIInfo; PFEATURE pFeature; POUTPUTBIN pOutputBin; DWORD dwFeatureIndex, dwOptionIndex; BOOL bRet = FALSE; #ifdef PSCRIPT { PPPDDATA pPpdData; POPTION pOption; PCSTR pstrKeywordName; // // For PostScript driver, PPD could have "*OpenUI *OutputOrder", which enables user to // select "Normal" or "Reverse" output order. This should have higher priority than // current output bin's output order or what *DefaultOutputOrder specifies. // pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pci->pRawData); ASSERT(pPpdData != NULL); if (pPpdData->dwOutputOrderIndex != INVALID_FEATURE_INDEX) { // // "OutputOrder" feature is available. Check it's current option selection. // pFeature = PGetIndexedFeature(pUIInfo, pPpdData->dwOutputOrderIndex); ASSERT(pFeature != NULL); dwOptionIndex = pci->pCombinedOptions[pPpdData->dwOutputOrderIndex].ubCurOptIndex; if ((pOption = PGetIndexedOption(pUIInfo, pFeature, dwOptionIndex)) && (pstrKeywordName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pOption->loKeywordName))) { // // Valid *OutputOrder option keywords are "Reverse" or "Normal". // if (strcmp(pstrKeywordName, "Reverse") == EQUAL_STRING) return TRUE; else if (strcmp(pstrKeywordName, "Normal") == EQUAL_STRING) return FALSE; } // // If we are here, the PPD must have wrong information in *OpenUI *OutputOrder. // We just ignore "OutputOrder" feature and continue. // } } #endif // PSCRIPT // // If the output bin order is NORMAL or there is no output bin // feature defined, then the page order is the user's selection. // if ((pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_OUTPUTBIN))) { dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature); dwOptionIndex = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex; pOutputBin = (POUTPUTBIN)PGetIndexedOption(pUIInfo, pFeature, dwOptionIndex); if (pOutputBin && pOutputBin->bOutputOrderReversed) { if (NOT_UNUSED_ITEM(pOutputBin->bOutputOrderReversed)) bRet = TRUE; else bRet = pUIInfo->dwFlags & FLAG_REVERSE_PRINT; } } else if (pUIInfo->dwFlags & FLAG_REVERSE_PRINT) bRet = TRUE; return bRet; } DWORD DwGetDrvCopies( PCOMMONINFO pci ) /*++ Routine Description: Get the printer copy count capability. Also take into account the collating option. Arguments: pci - Pointer to PCOMMONINFO Return Value: The number of copies the printer can do, with collating taken into consideration --*/ { DWORD dwRet; if ((pci->pdm->dmFields & DM_COLLATE) && pci->pdm->dmCollate == DMCOLLATE_TRUE && !PRINTER_SUPPORTS_COLLATE(pci)) dwRet = 1; else dwRet = min(pci->pUIInfo->dwMaxCopies, (DWORD)pci->pdm->dmCopies); return dwRet; } BOOL DrvQueryJobAttributes( HANDLE hPrinter, PDEVMODE pDevMode, DWORD dwLevel, LPBYTE lpAttributeInfo ) /*++ Routine Description: Negotiate EMF printing features (such as N-up and reverse-order printing) with the spooler Arguments: hPrinter - Handle to the current printer pDevMode - Pointer to input devmode dwLevel - Specifies the structure level for lpAttributeInfo lpAttributeInfo - Output buffer for returning EMF printing features Return Value: TRUE if successful, FALSE if there is an error --*/ { #if !defined(WINNT_40) PCOMMONINFO pci; PATTRIBUTE_INFO_1 pAttrInfo1; DWORD dwVal; BOOL bAppDoNup, bResult = FALSE; // // We can only handle AttributeInfo level 1 // if ( dwLevel != 1 && dwLevel != 2 && dwLevel != 3) { ERR(("Invalid level for DrvQueryJobAttributes: %d\n", dwLevel)); SetLastError(ERROR_INVALID_PARAMETER); return bResult; } // // Load basic printer information // if (! (pci = PLoadCommonInfo(hPrinter, NULL, 0)) || ! BFillCommonInfoPrinterData(pci) || ! BFillCommonInfoDevmode(pci, NULL, pDevMode) || ! BCombineCommonInfoOptionsArray(pci)) { VFreeCommonInfo(pci); return bResult; } VFixOptionsArrayWithDevmode(pci); (VOID) ResolveUIConflicts(pci->pRawData, pci->pCombinedOptions, MAX_COMBINED_OPTIONS, MODE_DOCUMENT_STICKY); VOptionsToDevmodeFields(pci, TRUE); if (! BUpdateUIInfo(pci)) { VFreeCommonInfo(pci); return bResult; } pAttrInfo1 = (PATTRIBUTE_INFO_1) lpAttributeInfo; bAppDoNup = ( (pci->pdm->dmFields & DM_NUP) && (pci->pdm->dmNup == DMNUP_ONEUP) ); if (bAppDoNup) { dwVal = 1; } else { switch (NUPOPTION(pci->pdmPrivate)) { case TWO_UP: dwVal = 2; break; case FOUR_UP: dwVal = 4; break; case SIX_UP: dwVal = 6; break; case NINE_UP: dwVal = 9; break; case SIXTEEN_UP: dwVal = 16; break; case BOOKLET_UP: dwVal = 2; break; case ONE_UP: default: dwVal = 1; break; } } pAttrInfo1->dwDrvNumberOfPagesPerSide = pAttrInfo1->dwJobNumberOfPagesPerSide = dwVal; pAttrInfo1->dwNupBorderFlags = BORDER_PRINT; pAttrInfo1->dwJobPageOrderFlags = REVPRINTOPTION(pci->pdmPrivate) ? REVERSE_PRINT : NORMAL_PRINT; pAttrInfo1->dwDrvPageOrderFlags = BGetPageOrderFlag(pci) ? REVERSE_PRINT : NORMAL_PRINT; // // Check for booklet // if ((NUPOPTION(pci->pdmPrivate) == BOOKLET_UP) && !bAppDoNup) { pAttrInfo1->dwJobNumberOfPagesPerSide = 2; pAttrInfo1->dwDrvNumberOfPagesPerSide = 1; pAttrInfo1->dwDrvPageOrderFlags |= BOOKLET_PRINT; } pAttrInfo1->dwJobNumberOfCopies = pci->pdm->dmCopies; pAttrInfo1->dwDrvNumberOfCopies = DwGetDrvCopies(pci); #ifdef UNIDRV // // Unidrv doesn't support N-up option. // pAttrInfo1->dwDrvNumberOfPagesPerSide = 1; #endif // // Unidrv assumes that automatic switching to monochrome // mode on a color printer is allowed unless disabled in GPD // if (dwLevel == 3) { #ifdef UNIDRV SHORT dmPrintQuality, dmYResolution; if (pci->pUIInfo->bChangeColorModeOnDoc && pci->pdm->dmColor == DMCOLOR_COLOR && BOkToChangeColorToMono(pci, pci->pdm, &dmPrintQuality, &dmYResolution) && GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_COLORMODE)) { ((PATTRIBUTE_INFO_3)pAttrInfo1)->dwColorOptimization = COLOR_OPTIMIZATION; ((PATTRIBUTE_INFO_3)pAttrInfo1)->dmPrintQuality = dmPrintQuality; ((PATTRIBUTE_INFO_3)pAttrInfo1)->dmYResolution = dmYResolution; } else #endif ((PATTRIBUTE_INFO_3)pAttrInfo1)->dwColorOptimization = NO_COLOR_OPTIMIZATION; } bResult = TRUE; FOREACH_OEMPLUGIN_LOOP(pci) if (HAS_COM_INTERFACE(pOemEntry)) { HRESULT hr; hr = HComOEMQueryJobAttributes( pOemEntry, hPrinter, pDevMode, dwLevel, lpAttributeInfo); if (hr == E_NOTIMPL || hr == E_NOINTERFACE) continue; bResult = SUCCEEDED(hr); } END_OEMPLUGIN_LOOP VFreeCommonInfo(pci); return bResult; #else // WINNT_40 return FALSE; #endif // WINNT_40 } VOID VUpdateBookletOption( PUIDATA pUiData, POPTITEM pCurItem ) /*++ Routine Description: Handle the dependencies between duplex, nup and booklet options Arguments: pUiData - UIDATA pCurItem - OPTITEM to currently selected item Return Value: None --*/ { PDRIVEREXTRA pdmExtra = pUiData->ci.pdmPrivate; DWORD dwFeatureIndex, dwOptionIndex, dwCount; PDUPLEX pDuplexOption = NULL; POPTITEM pDuplexItem, pNupItem; PFEATURE pDuplexFeature = NULL; pDuplexItem = pNupItem = NULL; // // 1. Booklet is enabled - turn duplex on // 3. Duplex is simplex, disable booklet, set to 1 up. // pDuplexFeature = GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_DUPLEX); pNupItem = PFindOptItemWithUserData(pUiData, NUP_ITEM); pDuplexItem = PFindOptItemWithUserData(pUiData, DUPLEX_ITEM); if (pDuplexFeature && pDuplexItem) { dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUiData->ci.pUIInfo, pDuplexFeature); dwOptionIndex = pUiData->ci.pCombinedOptions[dwFeatureIndex].ubCurOptIndex; pDuplexOption = PGetIndexedOption(pUiData->ci.pUIInfo, pDuplexFeature, dwOptionIndex); } if ((GETUSERDATAITEM(pCurItem->UserData) == NUP_ITEM) && pCurItem->Sel == BOOKLET_UP) { if (pDuplexOption && pDuplexOption->dwDuplexID == DMDUP_SIMPLEX) { pDuplexOption = PGetIndexedOption(pUiData->ci.pUIInfo, pDuplexFeature, 0); for (dwCount = 0 ; dwCount < pDuplexFeature->Options.dwCount; dwCount++) { if (pDuplexOption->dwDuplexID != DMDUP_SIMPLEX) { pDuplexItem->Sel = dwCount; pDuplexItem->Flags |= OPTIF_CHANGED; VUpdateOptionsArrayWithSelection(pUiData, pDuplexItem); break; } pDuplexOption++; } } } else if ((GETUSERDATAITEM(pCurItem->UserData) == DUPLEX_ITEM) && pDuplexOption) { if (pDuplexOption->dwDuplexID == DMDUP_SIMPLEX && pNupItem && pNupItem->Sel == BOOKLET_UP) { pNupItem->Sel = TWO_UP; pNupItem->Flags |= OPTIF_CHANGED; NUPOPTION(pdmExtra) = TWO_UP; } } } #ifdef UNIDRV VOID VSyncColorInformation( PUIDATA pUiData, POPTITEM pCurItem ) /*++ Routine Description: Arguments: Return Value: --*/ { POPTITEM pOptItem; PFEATURE pFeature; // // This is a hack to work around the fact that Unidrv has // two color options, color appearance and color mode option, // need to update the other once one is changed // pOptItem = (GETUSERDATAITEM(pCurItem->UserData) == COLOR_ITEM) ? PFindOptItemWithUserData(pUiData, COLORMODE_ITEM) : (GETUSERDATAITEM(pCurItem->UserData) == COLORMODE_ITEM) ? PFindOptItemWithUserData(pUiData, COLOR_ITEM) : NULL; if ((pOptItem != NULL) && (pFeature = GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_COLORMODE))) { DWORD dwFeature = GET_INDEX_FROM_FEATURE(pUiData->ci.pUIInfo, pFeature); // // Find either color appearance or color mode option // if (GETUSERDATAITEM(pCurItem->UserData) == COLOR_ITEM) { ChangeOptionsViaID( pUiData->ci.pInfoHeader, pUiData->ci.pCombinedOptions, GID_COLORMODE, pUiData->ci.pdm); pOptItem->Sel = pUiData->ci.pCombinedOptions[dwFeature].ubCurOptIndex; pOptItem->Flags |= OPTIF_CHANGED; } else // COLORMODE_ITEM { POPTION pColorMode; PCOLORMODEEX pColorModeEx; pColorMode = PGetIndexedOption( pUiData->ci.pUIInfo, pFeature, pCurItem->Sel); if (pColorMode) { pColorModeEx = OFFSET_TO_POINTER( pUiData->ci.pInfoHeader, pColorMode->loRenderOffset); if (pColorModeEx) { pOptItem->Sel = pColorModeEx->bColor ? 1: 0; VUnpackDocumentPropertiesItems(pUiData, pOptItem, 1); pOptItem->Flags |= OPTIF_CHANGED; } else { ERR(("pColorModeEx is NULL\n")); } } else { ERR(("pColorMode is NULL\n")); } } } } DWORD DwGetItemFromGID( PFEATURE pFeature ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD dwItem = 0; switch (pFeature->dwFeatureID) { case GID_PAGESIZE: dwItem = FORMNAME_ITEM; break; case GID_DUPLEX: dwItem = DUPLEX_ITEM; break; case GID_RESOLUTION: dwItem = RESOLUTION_ITEM; break; case GID_MEDIATYPE: dwItem = MEDIATYPE_ITEM; break; case GID_INPUTSLOT: dwItem = INPUTSLOT_ITEM; break; case GID_COLORMODE: dwItem = COLORMODE_ITEM; break; case GID_ORIENTATION: dwItem = ORIENTATION_ITEM; break; case GID_PAGEPROTECTION: dwItem = PAGE_PROTECT_ITEM; break; case GID_COLLATE: dwItem = COPIES_COLLATE_ITEM; break; case GID_HALFTONING: dwItem = HALFTONING_ITEM; break; default: dwItem = UNKNOWN_ITEM; break; } return dwItem; } PLISTNODE PGetMacroList( PUIDATA pUiData, POPTITEM pMacroItem, PGPDDRIVERINFO pDriverInfo ) /*++ Routine Description: Arguments: Return Value: --*/ { PUIINFO pUIInfo = pUiData->ci.pUIInfo; PLISTNODE pListNode = NULL; LISTINDEX liIndex; if (pMacroItem) { switch(pMacroItem->Sel) { case QS_BEST: liIndex = pUIInfo->liBestQualitySettings; break; case QS_DRAFT: liIndex = pUIInfo->liDraftQualitySettings; break; case QS_BETTER: liIndex = pUIInfo->liBetterQualitySettings; break; } pListNode = LISTNODEPTR(pDriverInfo, liIndex); } return pListNode; } VOID VUpdateQualitySettingOptions( PUIINFO pUIInfo, POPTITEM pQualityItem ) /*++ Routine Description: Arguments: Return Value: --*/ { POPTPARAM pParam; LISTINDEX liList; DWORD i; pParam = pQualityItem->pOptType->pOptParam; for (i = QS_BEST; i < QS_BEST + MAX_QUALITY_SETTINGS; i++) { switch(i) { case QS_BEST: liList = pUIInfo->liBestQualitySettings; break; case QS_BETTER: liList = pUIInfo->liBetterQualitySettings; break; case QS_DRAFT: liList = pUIInfo->liDraftQualitySettings; break; } if (liList == END_OF_LIST) { pParam->Flags |= OPTPF_DISABLED; pParam->dwReserved[0] = TRUE; } else { pParam->Flags &= ~OPTPF_DISABLED; pParam->dwReserved[0] = FALSE; } pParam++; } pQualityItem->Flags |= OPTIF_CHANGED; } VOID VMakeMacroSelections( PUIDATA pUiData, POPTITEM pCurItem ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD dwFeatureID, dwOptionID, dwItem, i; PUIINFO pUIInfo; POPTITEM pMacroItem, pOptItem; PFEATURE pFeature; PLISTNODE pListNode; PGPDDRIVERINFO pDriverInfo; BOOL bMatchFound = FALSE; // // Mark options array with the change to either // Macro selection, media type, color // // Update binary data // Make selection // if (pUiData->ci.pdmPrivate->dwFlags & DXF_CUSTOM_QUALITY) return; if (pCurItem) VUnpackDocumentPropertiesItems(pUiData, pCurItem, 1); pMacroItem = PFindOptItemWithUserData(pUiData, QUALITY_SETTINGS_ITEM); // // BUpdateUIInfo calls UpdateBinaryData to get new snapshot // for latest optionarray // if (pMacroItem == NULL || !BUpdateUIInfo(&pUiData->ci) ) return; pUIInfo = pUiData->ci.pUIInfo; pDriverInfo = OFFSET_TO_POINTER(pUiData->ci.pInfoHeader, pUiData->ci.pInfoHeader->loDriverOffset); // // Update the macro selection to reflect the current default // if (pCurItem && GETUSERDATAITEM(pCurItem->UserData) != QUALITY_SETTINGS_ITEM) { ASSERT(pUIInfo->defaultQuality != END_OF_LIST); if (pUIInfo->defaultQuality == END_OF_LIST) return; pMacroItem->Sel = pUIInfo->defaultQuality; VUnpackDocumentPropertiesItems(pUiData, pMacroItem, 1); pMacroItem->Flags |= OPTIF_CHANGED; } // // Determine which item to gray out based on the // liBestQualitySettings, liBetterQualitySettings, liDraftQualitySettings // VUpdateQualitySettingOptions(pUIInfo, pMacroItem); pListNode = PGetMacroList(pUiData, pMacroItem, pDriverInfo); // // Make the selction of Feature.Option // while (pListNode) { // // Search thru our list of OPTITEM for the matching // Feature // pOptItem = pUiData->pDrvOptItem; dwFeatureID = ((PQUALNAME)(&pListNode->dwData))->wFeatureID; dwOptionID = ((PQUALNAME)(&pListNode->dwData))->wOptionID; pFeature = (PFEATURE)((PBYTE)pUIInfo->pInfoHeader + pUIInfo->loFeatureList) + dwFeatureID; dwItem = DwGetItemFromGID(pFeature); for (i = 0; i < pUiData->dwDrvOptItem; i++) { if (ISPRINTERFEATUREITEM(pOptItem->UserData)) { PFEATURE pPrinterFeature = (PFEATURE)GETUSERDATAITEM(pOptItem->UserData); if (GET_INDEX_FROM_FEATURE(pUIInfo, pPrinterFeature) == dwFeatureID) bMatchFound = TRUE; } else { if (dwItem != UNKNOWN_ITEM && dwItem == GETUSERDATAITEM(pOptItem->UserData)) bMatchFound = TRUE; } if (bMatchFound) { pOptItem->Sel = dwOptionID; pOptItem->Flags |= OPTIF_CHANGED; VUnpackDocumentPropertiesItems(pUiData, pOptItem, 1); bMatchFound = FALSE; break; } pOptItem++; } pListNode = LISTNODEPTR(pDriverInfo, pListNode->dwNextItem); } } VOID VUpdateMacroSelection( PUIDATA pUiData, POPTITEM pCurItem ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD dwFeatureIndex; PFEATURE pFeature = NULL; PLISTNODE pListNode; POPTITEM pMacroItem; PGPDDRIVERINFO pDriverInfo; pMacroItem = PFindOptItemWithUserData(pUiData, QUALITY_SETTINGS_ITEM); if (pMacroItem == NULL) return; pDriverInfo = OFFSET_TO_POINTER(pUiData->ci.pInfoHeader, pUiData->ci.pInfoHeader->loDriverOffset); if (!(pFeature = PGetFeatureFromItem(pUiData->ci.pUIInfo, pCurItem, &dwFeatureIndex))) return; ASSERT(pDriverInfo); pListNode = PGetMacroList(pUiData, pMacroItem, pDriverInfo); while (pListNode) { if ( ((PQUALNAME)(&pListNode->dwData))->wFeatureID == (WORD)dwFeatureIndex) { pMacroItem->Flags |= OPTIF_ECB_CHECKED; _VUnpackDocumentOptions(pMacroItem, pUiData->ci.pdm); break; } pListNode = LISTNODEPTR(pDriverInfo, pListNode->dwNextItem); } } #endif //UNIDRV