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

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