Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1409 lines
36 KiB

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