1656 lines
37 KiB
C
1656 lines
37 KiB
C
|
/*++
|
|||
|
|
|||
|
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
|