|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
oemui.c
Abstract:
Support for OEM plugin UI modules
Environment:
Windows NT printer driver
Revision History:
02/13/97 -davidx- Created it.
--*/
#include "precomp.h"
//
// User mode helper functions for OEM plugins
//
const OEMUIPROCS OemUIHelperFuncs = { (PFN_DrvGetDriverSetting) BGetDriverSettingForOEM, (PFN_DrvUpdateUISetting) BUpdateUISettingForOEM, };
BOOL BPackOemPluginItems( PUIDATA pUiData )
/*++
Routine Description:
Call OEM plugin UI modules to let them add their OPTITEMs
Arguments:
pUiData - Points to UIDATA structure
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ PCOMMONINFO pci; PFN_OEMCommonUIProp pfnOEMCommonUIProp; POEMCUIPPARAM pOemCUIPParam; POPTITEM pOptItem; DWORD dwOptItem;
//
// Check if we're being called for the first time.
// We assume all OEM plugin items are always packed at the end.
//
if (pUiData->pOptItem == NULL) pUiData->dwDrvOptItem = pUiData->dwOptItem; else if (pUiData->dwDrvOptItem != pUiData->dwOptItem) { RIP(("Inconsistent OPTITEM count for driver items\n")); return FALSE; }
//
// Quick exit for no OEM plugin case
//
pci = (PCOMMONINFO) pUiData;
if (pci->pOemPlugins->dwCount == 0) return TRUE;
pOptItem = pUiData->pOptItem;
FOREACH_OEMPLUGIN_LOOP(pci)
if (!HAS_COM_INTERFACE(pOemEntry) && !(pfnOEMCommonUIProp = GET_OEM_ENTRYPOINT(pOemEntry, OEMCommonUIProp))) continue;
//
// Compose the input parameter for calling OEMCommonUI
//
pOemCUIPParam = pOemEntry->pParam;
if (pOemCUIPParam == NULL) { //
// Allocate memory for an OEMUI_PARAM structure
// during the first pass
//
if (pOptItem != NULL) continue;
if (! (pOemCUIPParam = HEAPALLOC(pci->hHeap, sizeof(OEMCUIPPARAM)))) { ERR(("Memory allocation failed\n")); return FALSE; }
pOemEntry->pParam = pOemCUIPParam; pOemCUIPParam->cbSize = sizeof(OEMCUIPPARAM); pOemCUIPParam->poemuiobj = pci->pOemPlugins->pdriverobj; pOemCUIPParam->hPrinter = pci->hPrinter; pOemCUIPParam->pPrinterName = pci->pPrinterName; pOemCUIPParam->hModule = pOemEntry->hInstance; pOemCUIPParam->hOEMHeap = pci->hHeap; pOemCUIPParam->pPublicDM = pci->pdm; pOemCUIPParam->pOEMDM = pOemEntry->pOEMDM; }
pOemCUIPParam->pDrvOptItems = pUiData->pDrvOptItem; pOemCUIPParam->cDrvOptItems = pUiData->dwDrvOptItem; pOemCUIPParam->pOEMOptItems = pOptItem; dwOptItem = pOemCUIPParam->cOEMOptItems;
//
// Actually call OEMCommonUI entrypoint
//
if (HAS_COM_INTERFACE(pOemEntry)) { HRESULT hr;
hr = HComOEMCommonUIProp( pOemEntry, (pUiData->iMode == MODE_DOCUMENT_STICKY) ? OEMCUIP_DOCPROP : OEMCUIP_PRNPROP, pOemCUIPParam);
if (hr == E_NOTIMPL) { HeapFree(pci->hHeap, 0, pOemCUIPParam); pOemEntry->pParam = NULL; continue; }
if (FAILED(hr)) { ERR(("OEMCommonUI failed for '%ws': %d\n", CURRENT_OEM_MODULE_NAME(pOemEntry), GetLastError()));
//
// OEM failure during the first pass is recoverable:
// we'll simply ignore OEM plugin items
//
if (pOptItem == NULL) { HeapFree(pci->hHeap, 0, pOemCUIPParam); pOemEntry->pParam = NULL; continue; } return FALSE; } } else { if (!pfnOEMCommonUIProp( (pUiData->iMode == MODE_DOCUMENT_STICKY) ? OEMCUIP_DOCPROP : OEMCUIP_PRNPROP, pOemCUIPParam)) { ERR(("OEMCommonUI failed for '%ws': %d\n", CURRENT_OEM_MODULE_NAME(pOemEntry), GetLastError())); #if 0
(VOID) IDisplayErrorMessageBox( NULL, 0, IDS_OEMERR_DLGTITLE, IDS_OEMERR_OPTITEM, CURRENT_OEM_MODULE_NAME(pOemEntry)); #endif
//
// OEM failure during the first pass is recoverable:
// we'll simply ignore OEM plugin items
//
if (pOptItem == NULL) { HeapFree(pci->hHeap, 0, pOemCUIPParam); pOemEntry->pParam = NULL; continue; }
return FALSE; } }
if (pOptItem != NULL) { //
// second pass - ensure the number of items is consistent
//
if (dwOptItem != pOemCUIPParam->cOEMOptItems) { RIP(("Inconsistent OPTITEM count reported by OEM plugin: %ws\n", CURRENT_OEM_MODULE_NAME(pOemEntry), GetLastError()));
return FALSE; }
pOptItem += pOemCUIPParam->cOEMOptItems; pUiData->pOptItem += pOemCUIPParam->cOEMOptItems; }
pUiData->dwOptItem += pOemCUIPParam->cOEMOptItems;
END_OEMPLUGIN_LOOP
return TRUE; }
LONG LInvokeOemPluginCallbacks( PUIDATA pUiData, PCPSUICBPARAM pCallbackParam, LONG lRet )
/*++
Routine Description:
Call OEM plugin module's callback function
Arguments:
pUiData - Points to UIDATA structure pCallbackParam - Points to callback parameter from compstui lRet - Return value after the driver has processed the callback
Return Value:
Return value for compstui
--*/
{ PCOMMONINFO pci = (PCOMMONINFO) pUiData; POEMCUIPPARAM pOemCUIPParam; LONG lNewResult;
//
// Quick exit for no OEM plugin case
//
if (pci->pOemPlugins->dwCount == 0) return lRet;
//
// Go through each OEM plugin UI module
//
FOREACH_OEMPLUGIN_LOOP(pci)
//
// Stop when anyone says don't exit
//
if (lRet == CPSUICB_ACTION_NO_APPLY_EXIT) { ASSERT(pCallbackParam->Reason == CPSUICB_REASON_APPLYNOW); break; }
//
// Get the address of OEM callback function and call it
//
pOemCUIPParam = pOemEntry->pParam;
if (pOemCUIPParam == NULL || pOemCUIPParam->OEMCUIPCallback == NULL) continue;
lNewResult = pOemCUIPParam->OEMCUIPCallback(pCallbackParam, pOemCUIPParam);
//
// Merge the new result with the existing result
//
switch (lNewResult) { case CPSUICB_ACTION_ITEMS_APPLIED: case CPSUICB_ACTION_NO_APPLY_EXIT:
ASSERT(pCallbackParam->Reason == CPSUICB_REASON_APPLYNOW); lRet = lNewResult; break;
case CPSUICB_ACTION_REINIT_ITEMS:
ASSERT(pCallbackParam->Reason != CPSUICB_REASON_APPLYNOW); lRet = lNewResult; break;
case CPSUICB_ACTION_OPTIF_CHANGED:
ASSERT(pCallbackParam->Reason != CPSUICB_REASON_APPLYNOW); if (lRet == CPSUICB_ACTION_NONE) lRet = lNewResult; break;
case CPSUICB_ACTION_NONE: break;
default:
RIP(("Invalid return value from OEM callback: '%ws'\n", CURRENT_OEM_MODULE_NAME(pOemEntry), GetLastError())); break; }
END_OEMPLUGIN_LOOP
return lRet; }
LRESULT OEMDocumentPropertySheets( PPROPSHEETUI_INFO pPSUIInfo, LPARAM lParam ) { HRESULT hr;
POEM_PLUGIN_ENTRY pOemEntry;
pOemEntry = ((POEMUIPSPARAM)(pPSUIInfo->lParamInit))->pOemEntry;
hr = HComOEMDocumentPropertySheets(pOemEntry, pPSUIInfo, lParam);
if (SUCCEEDED(hr)) return 1;
return -1; }
LRESULT OEMDevicePropertySheets( PPROPSHEETUI_INFO pPSUIInfo, LPARAM lParam ) { HRESULT hr;
POEM_PLUGIN_ENTRY pOemEntry;
pOemEntry = ((POEMUIPSPARAM)(pPSUIInfo->lParamInit))->pOemEntry;
hr = HComOEMDevicePropertySheets(pOemEntry, pPSUIInfo, lParam);
if (SUCCEEDED(hr)) return 1;
return -1; }
BOOL BAddOemPluginPages( PUIDATA pUiData, DWORD dwFlags )
/*++
Routine Description:
Call OEM plugin UI modules to let them add their own property sheet pages
Arguments:
pUiData - Points to UIDATA structure dwFlags - Flags from DOCUMENTPROPERTYHEADER or DEVICEPROPERTYHEADER
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ PCOMMONINFO pci = (PCOMMONINFO) pUiData; FARPROC pfnOEMPropertySheets; POEMUIPSPARAM pOemUIPSParam;
//
// Quick exit for no OEM plugin case
//
if (pci->pOemPlugins->dwCount == 0) return TRUE;
//
// Add the property sheet for each OEM plugin UI module
//
FOREACH_OEMPLUGIN_LOOP(pci)
//
// get the address of appropriate OEM entrypoint
//
if (HAS_COM_INTERFACE(pOemEntry)) { if (pUiData->iMode == MODE_DOCUMENT_STICKY) pfnOEMPropertySheets = (FARPROC)OEMDocumentPropertySheets; else pfnOEMPropertySheets = (FARPROC)OEMDevicePropertySheets; } else { if (pUiData->iMode == MODE_DOCUMENT_STICKY) { pfnOEMPropertySheets = (FARPROC) GET_OEM_ENTRYPOINT(pOemEntry, OEMDocumentPropertySheets); } else { pfnOEMPropertySheets = (FARPROC) GET_OEM_ENTRYPOINT(pOemEntry, OEMDevicePropertySheets); }
if (pfnOEMPropertySheets == NULL) continue; }
//
// Collect input parameters to be passed to OEM plugin
//
if ((pOemUIPSParam = HEAPALLOC(pci->hHeap, sizeof(OEMUIPSPARAM))) == NULL) { ERR(("Memory allocation failed\n")); return FALSE; }
pOemUIPSParam->cbSize = sizeof(OEMUIPSPARAM); pOemUIPSParam->poemuiobj = pci->pOemPlugins->pdriverobj; pOemUIPSParam->hPrinter = pci->hPrinter; pOemUIPSParam->pPrinterName = pci->pPrinterName; pOemUIPSParam->hModule = pOemEntry->hInstance; pOemUIPSParam->hOEMHeap = pci->hHeap; pOemUIPSParam->pPublicDM = pci->pdm; pOemUIPSParam->pOEMDM = pOemEntry->pOEMDM; pOemUIPSParam->dwFlags = dwFlags; pOemUIPSParam->pOemEntry = pOemEntry;
//
// call compstui to add the OEM plugin property sheets
//
if (pUiData->pfnComPropSheet(pUiData->hComPropSheet, CPSFUNC_ADD_PFNPROPSHEETUI, (LPARAM) pfnOEMPropertySheets, (LPARAM) pOemUIPSParam) <= 0) { VERBOSE(("Couldn't add property sheet pages for '%ws'\n", CURRENT_OEM_MODULE_NAME(pOemEntry), GetLastError())); }
END_OEMPLUGIN_LOOP
return TRUE; }
BOOL APIENTRY BGetDriverSettingForOEM( PCOMMONINFO pci, PCSTR pFeatureKeyword, PVOID pOutput, DWORD cbSize, PDWORD pcbNeeded, PDWORD pdwOptionsReturned )
/*++
Routine Description:
Provide OEM plugins access to driver private settings
Arguments:
pci - Points to basic printer information pFeatureKeyword - Specifies the keyword the caller is interested in pOutput - Points to output buffer cbSize - Size of output buffer pcbNeeded - Returns the expected size of output buffer pdwOptionsReturned - Returns the number of options selected
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ ULONG_PTR dwIndex; BOOL bResult;
ASSERT(pci->pvStartSign == pci);
if ((pci == NULL) || (pci->pvStartSign != pci)) { WARNING(("BGetDriverSettingForOEM: invalid pci")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
//
// This is not very portable: If the pointer value for pFeatureKeyword
// is less than 0x10000, we assume that the pointer value actually
// specifies a predefined index.
//
//
// Following ASSERT is removed for Win64
//
// ASSERT(sizeof(pFeatureKeyword) == sizeof(DWORD));
//
dwIndex = (ULONG_PTR)pFeatureKeyword;
if (dwIndex >= OEMGDS_MIN_DOCSTICKY && dwIndex < OEMGDS_MIN_PRINTERSTICKY) { if (pci->pdm == NULL) goto setting_not_available;
bResult = BGetDevmodeSettingForOEM( pci->pdm, (DWORD)dwIndex, pOutput, cbSize, pcbNeeded);
if (bResult) *pdwOptionsReturned = 1; } else if (dwIndex >= OEMGDS_MIN_PRINTERSTICKY && dwIndex < OEMGDS_MAX) { if (pci->pPrinterData == NULL) goto setting_not_available;
bResult = BGetPrinterDataSettingForOEM( pci->pPrinterData, (DWORD)dwIndex, pOutput, cbSize, pcbNeeded);
if (bResult) *pdwOptionsReturned = 1; } else { if (pci->pCombinedOptions == NULL) goto setting_not_available;
bResult = BGetGenericOptionSettingForOEM( pci->pUIInfo, pci->pCombinedOptions, pFeatureKeyword, pOutput, cbSize, pcbNeeded, pdwOptionsReturned); }
return bResult;
setting_not_available:
WARNING(("Requested driver setting not available: %d\n", pFeatureKeyword)); SetLastError(ERROR_NOT_SUPPORTED); return FALSE; }
BOOL BUpdateUISettingForOEM( PCOMMONINFO pci, PVOID pOptItem, DWORD dwPreviousSelection, DWORD dwMode )
/*++
Routine Description:
Update the UI settings in optionsarray for OEM.
Arguments:
pci - Points to basic printer information pOptItem - Points to the current OPTITEM
Return Value:
TRUE if successful, FALSE if there is an error such as conflict and user wants to cancel.
--*/
{ POPTITEM pCurItem = pOptItem; PUIDATA pUiData = (PUIDATA)pci;
ASSERT(pci->pvStartSign == pci);
if ((pci == NULL) || (pci->pvStartSign != pci)) { WARNING(("BUpdateUISettingForOEM: invalid pci")); return FALSE; }
if (ICheckConstraintsDlg(pUiData, pCurItem, 1, FALSE) == CONFLICT_CANCEL) { //
// If there is a conflict and the user clicked
// CANCEL to restore the original selection.
// CONFLICT_CANCEL, restore the old setting
//
return FALSE; }
if (dwMode == OEMCUIP_DOCPROP) { //
// We use FLAG_WITHIN_PLUGINCALL to indicate we are within the UI helper
// function call issued by OEM plugin. This is needed to fix bug #90923.
//
pUiData->ci.dwFlags |= FLAG_WITHIN_PLUGINCALL; VUnpackDocumentPropertiesItems(pUiData, pCurItem, 1); pUiData->ci.dwFlags &= ~FLAG_WITHIN_PLUGINCALL;
VPropShowConstraints(pUiData, MODE_DOCANDPRINTER_STICKY); } else { VUpdateOptionsArrayWithSelection(pUiData, pCurItem); VPropShowConstraints(pUiData, MODE_PRINTER_STICKY); }
//
// Record the fact that one of our OPTITEM selection has been changed by plugin's
// call of helper function DrvUpdateUISetting. This is necessary so that at the
// APPLYNOW time we know constraints could exist even though user hasn't touched
// any of our OPTITEMs.
//
pUiData->ci.dwFlags |= FLAG_PLUGIN_CHANGED_OPTITEM;
return TRUE; }
BOOL BUpgradeRegistrySettingForOEM( HANDLE hPrinter, PCSTR pFeatureKeyword, PCSTR pOptionKeyword )
/*++
Routine Description:
Set the Feature.Option request to our options array. OEM will only call this function at OEMUpgradeDriver to upgrade their registry setttings into our optionsarray saved in our PRINTERDATA
Arguments:
hPrinter - Handle of the Printer pFeatureKeyword - Specifies the keyword the caller is interested in pOptionKeyword - Specifies the keyword the caller is interested in
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFEATURE pFeature; POPTION pOption; DWORD dwFeatureCount, i, j; BOOL bFeatureFound, bOptionFound, bResult = FALSE; PCSTR pKeywordName; POPTSELECT pOptionsArray = NULL; PDRIVER_INFO_3 pDriverInfo3 = NULL; PRAWBINARYDATA pRawData = NULL; PINFOHEADER pInfoHeader = NULL; PUIINFO pUIInfo = NULL; PPRINTERDATA pPrinterData = NULL; OPTSELECT DocOptions[MAX_PRINTER_OPTIONS];
//
// Get information about the printer driver
//
bResult = bFeatureFound = bOptionFound = FALSE;
if ((pDriverInfo3 = MyGetPrinterDriver(hPrinter, NULL, 3)) == NULL) { ERR(("Cannot get printer driver info: %d\n", GetLastError())); goto upgrade_registry_exit; }
// ENTER_CRITICAL_SECTION();
pRawData = LoadRawBinaryData(pDriverInfo3->pDataFile);
// LEAVE_CRITICAL_SECTION();
if (pRawData == NULL) goto upgrade_registry_exit;
if (!(pPrinterData = MemAllocZ(sizeof(PRINTERDATA))) || !( BGetPrinterProperties(hPrinter, pRawData, pPrinterData))) {
ERR(("Cannot get printer data info: %d\n", GetLastError())); goto upgrade_registry_exit; }
//
// Allocate memory for combined optionsarray
//
if (!(pOptionsArray = MemAllocZ(MAX_COMBINED_OPTIONS * sizeof (OPTSELECT)))) goto upgrade_registry_exit;
if (! InitDefaultOptions(pRawData, DocOptions, MAX_PRINTER_OPTIONS, MODE_DOCUMENT_STICKY)) { goto upgrade_registry_exit; }
//
// Combine doc sticky options with printer sticky items
//
CombineOptionArray(pRawData, pOptionsArray, MAX_COMBINED_OPTIONS, DocOptions, pPrinterData->aOptions);
//
// Get an updated instance of printer description data
//
pInfoHeader = InitBinaryData(pRawData, NULL, pOptionsArray);
if (pInfoHeader == NULL) { ERR(("InitBinaryData failed\n")); goto upgrade_registry_exit; }
if (!(pUIInfo = OFFSET_TO_POINTER(pInfoHeader, pInfoHeader->loUIInfoOffset))) goto upgrade_registry_exit;
//
// Look for feature.option index
//
pFeature = PGetIndexedFeature(pUIInfo, 0); dwFeatureCount = pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures;
if (pFeature && dwFeatureCount) { for (i = 0; i < dwFeatureCount; i++) { pKeywordName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pFeature->loKeywordName); if (strcmp(pKeywordName, pFeatureKeyword) == EQUAL_STRING) { bFeatureFound = TRUE; break; } pFeature++; } }
if (bFeatureFound) { pOption = PGetIndexedOption(pUIInfo, pFeature, 0);
for (j = 0; j < pFeature->Options.dwCount; j++) { pKeywordName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pOption->loKeywordName); if (strcmp(pKeywordName, pOptionKeyword) == EQUAL_STRING) { bOptionFound = TRUE; break; } pOption++; } }
if (bFeatureFound && bOptionFound) { pOptionsArray[i].ubCurOptIndex = (BYTE)j;
//
// Resolve conflicts
//
if (!ResolveUIConflicts( pRawData, pOptionsArray, MAX_COMBINED_OPTIONS, MODE_DOCANDPRINTER_STICKY)) { VERBOSE(("Resolved conflicting printer feature selections.\n")); }
SeparateOptionArray(pRawData, pOptionsArray, pPrinterData->aOptions, MAX_PRINTER_OPTIONS, MODE_PRINTER_STICKY );
if (!BSavePrinterProperties(hPrinter, pRawData, pPrinterData, sizeof(PRINTERDATA))) { ERR(("BSavePrinterProperties failed\n")); bResult = FALSE; } else bResult = TRUE; }
upgrade_registry_exit:
if (pInfoHeader) FreeBinaryData(pInfoHeader);
if (pRawData) UnloadRawBinaryData(pRawData);
if (pPrinterData) MemFree(pPrinterData);
if (pDriverInfo3) MemFree(pDriverInfo3);
if (pOptionsArray) MemFree(pOptionsArray);
return bResult; }
#ifdef PSCRIPT
#ifndef WINNT_40
/*++
Routine Name:
HQuerySimulationSupport
Routine Description:
In the case of UI replacement, we allows IHV to query for print processor simulation support so they can provide simulated features on their UI.
We won't enforce hooking out QueryJobAttribute w/o UI replacement here. We will do it at DrvQueryJobAttributes.
Arguments:
hPrinter - printer handle dwLevel - interested level of spooler simulation capability info structure pCaps - pointer to output buffer cbSize - size in bytes of output buffer pcbNeeded - buffer size in bytes needed to store the interested info structure
Return Value:
S_OK if succeeded E_OUTOFMEMORY if output buffer is not big enough E_NOTIMPL if the interested level is not supported E_FAIL if encountered other internal error
Last Error:
None
--*/ HRESULT HQuerySimulationSupport( IN HANDLE hPrinter, IN DWORD dwLevel, OUT PBYTE pCaps, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { PRINTPROCESSOR_CAPS_1 SplCaps; PSIMULATE_CAPS_1 pSimCaps; DWORD cbNeeded;
//
// currently only Level 1 is supported
//
if (dwLevel != 1) { return E_NOTIMPL; }
cbNeeded = sizeof(SIMULATE_CAPS_1);
if (pcbNeeded) { *pcbNeeded = cbNeeded; }
if (!pCaps || cbSize < cbNeeded) { return E_OUTOFMEMORY; }
//
// Since VGetSpoolerEmfCaps doesn't return error code, we
// are using the dwLevel field to detect if the call succeeds.
// If succeeds, dwLevel should be set as 1.
//
SplCaps.dwLevel = 0;
VGetSpoolerEmfCaps(hPrinter, NULL, NULL, sizeof(PRINTPROCESSOR_CAPS_1), &SplCaps );
if (SplCaps.dwLevel != 1) { ERR(("VGetSpoolerEmfCaps failed\n")); return E_FAIL; }
//
// BUGBUG, we should get a new PRINTPROCESSOR_CAPS level to include all
// these information instead of filling it out here. Need
// new PRINTPROCESSOR_CAPS
//
pSimCaps = (PSIMULATE_CAPS_1)pCaps;
pSimCaps->dwLevel = 1; pSimCaps->dwPageOrderFlags = SplCaps.dwPageOrderFlags; pSimCaps->dwNumberOfCopies = SplCaps.dwNumberOfCopies; pSimCaps->dwNupOptions = SplCaps.dwNupOptions;
//
// PRINTPROCESSOR_CAPS_1 is designed without an explicit field for
// collate simulation. So before its CAPS_2 is introduced, we have
// to assume that if reverse printing is supported, then collate
// simulation is also supported.
//
if (SplCaps.dwPageOrderFlags & REVERSE_PRINT) { pSimCaps->dwCollate = 1; } else { pSimCaps->dwCollate = 0; }
return S_OK; }
#endif // !WINNT_40
/*++
Routine Name:
HEnumConstrainedOptions
Routine Description:
enumerate the constrained option keyword name list in the specified feature
Arguments:
poemuiobj - pointer to driver context object dwFlags - flags for the enumeration operation pszFeatureKeyword - feature keyword name pmszConstrainedOptionList - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK if succeeds E_OUTOFMEMORY if output data buffer size is not big enough E_INVALIDARG if feature keyword name is not recognized, or the feature's stickiness doesn't match current sticky-mode E_FAIL if other internal failures are encountered
Last Error:
None
--*/ HRESULT HEnumConstrainedOptions( IN POEMUIOBJ poemuiobj, IN DWORD dwFlags, IN PCSTR pszFeatureKeyword, OUT PSTR pmszConstrainedOptionList, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { PCOMMONINFO pci = (PCOMMONINFO)poemuiobj; PUIDATA pUiData; PFEATURE pFeature; POPTION pOption; DWORD dwFeatureIndex, dwIndex; PBOOL pabEnabledOptions = NULL; PSTR pCurrentOut; DWORD cbNeeded; INT cbRemain; HRESULT hr;
pUiData = (PUIDATA)pci;
if (!pszFeatureKeyword || (pFeature = PGetNamedFeature(pci->pUIInfo, pszFeatureKeyword, &dwFeatureIndex)) == NULL) { WARNING(("HEnumConstrainedOptions: invalid feature\n"));
//
// Even though we could return right here, we still use goto to maintain single exit point.
//
hr = E_INVALIDARG; goto exit; }
//
// pUiData->iMode can have 2 modes: MODE_DOCUMENT_STICKY and MODE_PRINTER_STICKY. See PFillUiData().
// In MODE_DOCUMENT_STICKY mode, we only support doc-sticky features.
// In MODE_PRINTER_STICKY mode, we only support printer-sticky features.
//
// This is because in function PFillUiData(), it only fills devmode in MODE_DOCUMENT_STICKY mode.
// Then in BCombineCommonInfoOptionsArray(), if devmode option array is not available, the PPD parser
// will use OPTION_INDEX_ANY for any doc-sticky features.
//
if ((pUiData->iMode == MODE_DOCUMENT_STICKY && pFeature->dwFeatureType == FEATURETYPE_PRINTERPROPERTY) || (pUiData->iMode == MODE_PRINTER_STICKY && pFeature->dwFeatureType != FEATURETYPE_PRINTERPROPERTY)) { VERBOSE(("HEnumConstrainedOptions: mismatch iMode=%d, dwFeatureType=%d\n", pUiData->iMode, pFeature->dwFeatureType)) ;
hr = E_INVALIDARG; goto exit; }
if (pFeature->Options.dwCount) { if ((pabEnabledOptions = MemAllocZ(pFeature->Options.dwCount * sizeof(BOOL))) == NULL) { ERR(("HEnumConstrainedOptions: memory alloc failed\n")); hr = E_FAIL; goto exit; }
//
// Get the feature's enabled option list.
//
// See VPropShowConstraints() in docprop.c and prnprop.c for using different
// modes to call EnumEnabledOptions().
//
if (pUiData->iMode == MODE_DOCUMENT_STICKY) { EnumEnabledOptions(pci->pRawData, pci->pCombinedOptions, dwFeatureIndex, pabEnabledOptions, MODE_DOCANDPRINTER_STICKY); } else { EnumEnabledOptions(pci->pRawData, pci->pCombinedOptions, dwFeatureIndex, pabEnabledOptions, MODE_PRINTER_STICKY); } } else { RIP(("HEnumConstrainedOptions: feature %s has no options\n", pszFeatureKeyword));
//
// continue so we will output the empty string with only the NUL character
//
}
pCurrentOut = pmszConstrainedOptionList; cbNeeded = 0; cbRemain = (INT)cbSize;
pOption = OFFSET_TO_POINTER(pci->pInfoHeader, pFeature->Options.loOffset);
ASSERT(pOption || pFeature->Options.dwCount == 0);
if (pOption == NULL && pFeature->Options.dwCount != 0) { hr = E_FAIL; goto exit; }
for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++) { if (!pabEnabledOptions[dwIndex]) { DWORD dwNameSize; PSTR pszKeywordName;
pszKeywordName = OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData, pOption->loKeywordName);
ASSERT(pszKeywordName);
if (pszKeywordName == NULL) { hr = E_FAIL; goto exit; }
//
// count in the NUL character between constrained option keywords
//
dwNameSize = strlen(pszKeywordName) + 1;
if (pCurrentOut && cbRemain >= (INT)dwNameSize) { CopyMemory(pCurrentOut, pszKeywordName, dwNameSize); pCurrentOut += dwNameSize; }
cbRemain -= dwNameSize; cbNeeded += dwNameSize; }
pOption = (POPTION)((PBYTE)pOption + pFeature->dwOptionSize); }
//
// remember the last NUL terminator for the MULTI_SZ output string
//
cbNeeded++;
if (pcbNeeded) { *pcbNeeded = cbNeeded; }
if (!pCurrentOut || cbRemain < 1) { hr = E_OUTOFMEMORY; goto exit; }
*pCurrentOut = NUL;
//
// Succeeded
//
hr = S_OK;
exit:
MemFree(pabEnabledOptions); return hr; }
/*++
Routine Name:
HWhyConstrained
Routine Description:
get feature/option keyword pair that constrains the given feature/option pair
Arguments:
poemuiobj - pointer to driver context object dwFlags - flags for this operation pszFeatureKeyword - feature keyword name pszOptionKeyword - option keyword name pmszReasonList - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data
Return Value:
S_OK if succeeds E_OUTOFMEMORY if output data buffer size is not big enough E_INVALIDARG if the feature keyword name or option keyword name is not recognized, or the feature's stickiness doesn't match current sticky-mode
Last Error:
None
--*/ HRESULT HWhyConstrained( IN POEMUIOBJ poemuiobj, IN DWORD dwFlags, IN PCSTR pszFeatureKeyword, IN PCSTR pszOptionKeyword, OUT PSTR pmszReasonList, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { PCOMMONINFO pci = (PCOMMONINFO)poemuiobj; PUIDATA pUiData; PFEATURE pFeature; POPTION pOption; DWORD dwFeatureIndex, dwOptionIndex; CONFLICTPAIR ConflictPair; BOOL bConflictFound; PSTR pszConfFeatureName = NULL, pszConfOptionName = NULL; CHAR emptyString[1] = {0}; DWORD cbConfFeatureKeySize = 0, cbConfOptionKeySize = 0; DWORD cbNeeded = 0;
pUiData = (PUIDATA)pci;
if (!pszFeatureKeyword || (pFeature = PGetNamedFeature(pci->pUIInfo, pszFeatureKeyword, &dwFeatureIndex)) == NULL) { WARNING(("HWhyConstrained: invalid feature\n")); return E_INVALIDARG; }
if (!pszOptionKeyword || (pOption = PGetNamedOption(pci->pUIInfo, pFeature, pszOptionKeyword, &dwOptionIndex)) == NULL) { WARNING(("HWhyConstrained: invalid option\n")); return E_INVALIDARG; }
//
// See comments in HEnumConstrainedOptions() for following stickiness mode check.
//
if ((pUiData->iMode == MODE_DOCUMENT_STICKY && pFeature->dwFeatureType == FEATURETYPE_PRINTERPROPERTY) || (pUiData->iMode == MODE_PRINTER_STICKY && pFeature->dwFeatureType != FEATURETYPE_PRINTERPROPERTY)) { VERBOSE(("HWhyConstrained: mismatch iMode=%d, dwFeatureType=%d\n",pUiData->iMode, pFeature->dwFeatureType)); return E_INVALIDARG; }
//
// Get the feature/option pair that constrains the feature/option pair client is querying for.
//
bConflictFound = EnumNewPickOneUIConflict(pci->pRawData, pci->pCombinedOptions, dwFeatureIndex, dwOptionIndex, &ConflictPair);
if (bConflictFound) { PFEATURE pConfFeature; POPTION pConfOption; DWORD dwConfFeatureIndex, dwConfOptionIndex;
//
// ConflictPair has the feature with higher priority as dwFeatureIndex1.
//
if (dwFeatureIndex == ConflictPair.dwFeatureIndex1) { dwConfFeatureIndex = ConflictPair.dwFeatureIndex2; dwConfOptionIndex = ConflictPair.dwOptionIndex2; } else { dwConfFeatureIndex = ConflictPair.dwFeatureIndex1; dwConfOptionIndex = ConflictPair.dwOptionIndex1; }
pConfFeature = PGetIndexedFeature(pci->pUIInfo, dwConfFeatureIndex); ASSERT(pConfFeature);
pConfOption = PGetIndexedOption(pci->pUIInfo, pConfFeature, dwConfOptionIndex);
//
// We don't expect pConfOption to be NULL here. Use the ASSERT to catch cases we missed.
//
ASSERT(pConfOption);
pszConfFeatureName = OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData, pConfFeature->loKeywordName); ASSERT(pszConfFeatureName);
if (pConfOption) { pszConfOptionName = OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData, pConfOption->loKeywordName); ASSERT(pszConfOptionName); } else { pszConfOptionName = &(emptyString[0]); }
//
// count in the 2 NUL characters: one after feature name, one after option name.
//
cbConfFeatureKeySize = strlen(pszConfFeatureName) + 1; cbConfOptionKeySize = strlen(pszConfOptionName) + 1; }
//
// count in the last NUL characters at the end.
//
cbNeeded = cbConfFeatureKeySize + cbConfOptionKeySize + 1;
if (pcbNeeded) { *pcbNeeded = cbNeeded; }
if (!pmszReasonList || cbSize < cbNeeded) { return E_OUTOFMEMORY; }
if (bConflictFound) { ASSERT(pszConfFeatureName && pszConfOptionName);
CopyMemory(pmszReasonList, pszConfFeatureName, cbConfFeatureKeySize); pmszReasonList += cbConfFeatureKeySize;
CopyMemory(pmszReasonList, pszConfOptionName, cbConfOptionKeySize); pmszReasonList += cbConfOptionKeySize; }
//
// Now the NUL at the end to finish the MULTI_SZ output string.
//
*pmszReasonList = NUL;
return S_OK; }
#endif // PSCRIPT
|