windows-nt/Source/XPSP1/NT/printscan/print/drivers/usermode/driverui/docprop.c
2020-09-26 16:20:57 +08:00

3337 lines
81 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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