mirror of https://github.com/lianthony/NT4.0
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.
1710 lines
36 KiB
1710 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
psui.c
|
|
|
|
Abstract:
|
|
|
|
PostScript driver user interface
|
|
|
|
[Environment:]
|
|
|
|
Win32 subsystem, PostScript driver, user mode
|
|
|
|
Revision History:
|
|
|
|
06/21/95 -davidx-
|
|
Created it.
|
|
|
|
mm/dd/yy -author-
|
|
description
|
|
|
|
--*/
|
|
|
|
#include "psui.h"
|
|
|
|
// Semaphore for protecting critical sections
|
|
|
|
CRITICAL_SECTION psuiSemaphore;
|
|
|
|
// Handle to cached PPD object
|
|
|
|
HPPD cachedPpdData;
|
|
WORD cacheRefCount;
|
|
INT _debugLevel = 0;
|
|
|
|
|
|
|
|
VOID
|
|
InitPpdCache(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize PPD file cache
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
cachedPpdData = NULL;
|
|
cacheRefCount = 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
FlushPpdCache(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deinitialize PPD file cache
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
// Need to be in a critical region since
|
|
// we access shared data here
|
|
|
|
EnterCriticalSection(&psuiSemaphore);
|
|
|
|
if (cachedPpdData != NULL) {
|
|
|
|
// There shouldn't be anyone still accessing
|
|
// the cached PPD data when it's flushed
|
|
|
|
if (cacheRefCount > 0) {
|
|
|
|
DBGMSG(DBG_LEVEL_ERROR, "Trying to flush PPD cache while refcount != 0!\n");
|
|
cacheRefCount = 0;
|
|
}
|
|
|
|
PpdDelete(cachedPpdData);
|
|
cachedPpdData = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection(&psuiSemaphore);
|
|
}
|
|
|
|
|
|
|
|
HPPD
|
|
LoadPpdFile(
|
|
HANDLE hPrinter,
|
|
BOOL useCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load PPD file associated with a printer
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Printer handle
|
|
useCache - Use the cached BPD data if possible
|
|
|
|
Return Value:
|
|
|
|
PPD object associated with a printer
|
|
NULL if an error has occured
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cbNeeded;
|
|
HPPD hppd = NULL;
|
|
PDRIVER_INFO_2 pDriverInfo2;
|
|
|
|
//
|
|
// Find out how much space required for driver info.
|
|
//
|
|
|
|
if (pDriverInfo2 = MyGetPrinterDriver(hPrinter, 2)) {
|
|
|
|
EnterCriticalSection(&psuiSemaphore);
|
|
|
|
if (useCache &&
|
|
cachedPpdData != NULL &&
|
|
_wcsicmp(cachedPpdData->pwstrFilename, pDriverInfo2->pDataFile) == EQUAL_STRING)
|
|
{
|
|
// Requested ppd file is already in the cache;
|
|
// simply increment the cache reference count
|
|
|
|
cacheRefCount++;
|
|
hppd = cachedPpdData;
|
|
|
|
} else {
|
|
|
|
// Ppd file wasn't cached; parse it now.
|
|
|
|
hppd = PpdCreate(pDriverInfo2->pDataFile);
|
|
|
|
// Cache the newly parsed ppd file if possible
|
|
|
|
if (hppd != NULL && cacheRefCount == 0) {
|
|
|
|
if (cachedPpdData != NULL)
|
|
PpdDelete(cachedPpdData);
|
|
|
|
cachedPpdData = hppd;
|
|
cacheRefCount = 1;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&psuiSemaphore);
|
|
MEMFREE(pDriverInfo2);
|
|
}
|
|
|
|
return hppd;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
UnloadPpdFile(
|
|
HPPD hppd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unload a PPD file object. Do nothing if the PPD object was cached.
|
|
Otherwise, delete the PPD object from memory.
|
|
|
|
Arguments:
|
|
|
|
hppd - Pointer to PPD object
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
EnterCriticalSection(&psuiSemaphore);
|
|
|
|
if (hppd != cachedPpdData) {
|
|
|
|
Warning(("PPD object was not cached.\n"));
|
|
PpdDelete(hppd);
|
|
|
|
} else {
|
|
|
|
Assert(cacheRefCount > 0);
|
|
cacheRefCount--;
|
|
}
|
|
|
|
LeaveCriticalSection(&psuiSemaphore);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
AddPrinterForms(
|
|
HANDLE hPrinter,
|
|
HPPD hppd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add printer forms to the forms database
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Handle to printer
|
|
hppd - Handle to PPD object
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PMEDIAOPTION pMediaOption;
|
|
FORM_INFO_1 formInfo;
|
|
WCHAR wcbuf[CCHFORMNAME];
|
|
DWORD dwValue, dwType, cb;
|
|
|
|
//
|
|
// Check we've added printer forms already. Note that if the PPD
|
|
// file is changed and new printer forms are added, we won't pick them up here.
|
|
//
|
|
|
|
if (GetPrinterData(hPrinter,
|
|
STDSTR_FORMS_ADDED,
|
|
&dwType,
|
|
(PBYTE) &dwValue,
|
|
sizeof(dwValue),
|
|
&cb) == ERROR_SUCCESS &&
|
|
dwValue > 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
formInfo.Flags = FORM_PRINTER;
|
|
formInfo.pName = wcbuf;
|
|
|
|
if (hppd->pPageSizes == NULL)
|
|
return TRUE;
|
|
|
|
for (pMediaOption = (PMEDIAOPTION) hppd->pPageSizes->pUiOptions;
|
|
pMediaOption != NULL;
|
|
pMediaOption = pMediaOption->pNext)
|
|
{
|
|
if (pMediaOption->dimension.width == 0 ||
|
|
pMediaOption->dimension.height == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Paper name
|
|
//
|
|
|
|
CopyStr2Unicode(wcbuf, GetXlatedName(pMediaOption), CCHFORMNAME);
|
|
|
|
//
|
|
// Paper size - remember FORM_INFO_1 uses micron unit while
|
|
// our internal unit is point in 24.8 fixed-point format.
|
|
//
|
|
|
|
formInfo.Size.cx = PSRealToMicron(pMediaOption->dimension.width);
|
|
formInfo.Size.cy = PSRealToMicron(pMediaOption->dimension.height);
|
|
|
|
//
|
|
// Imageable area - For driver-defined forms, all margins should be set to 0.
|
|
//
|
|
|
|
formInfo.ImageableArea.left =
|
|
formInfo.ImageableArea.top = 0;
|
|
formInfo.ImageableArea.right = formInfo.Size.cx;
|
|
formInfo.ImageableArea.bottom = formInfo.Size.cy;
|
|
|
|
AddForm(hPrinter, 1, (PBYTE) &formInfo);
|
|
}
|
|
|
|
//
|
|
// Indicate the forms have been added by SUR driver
|
|
//
|
|
|
|
dwValue = 2;
|
|
SetPrinterData(hPrinter,
|
|
STDSTR_FORMS_ADDED,
|
|
REG_DWORD,
|
|
(PBYTE) &dwValue,
|
|
sizeof(dwValue));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
RemovePrinterForms(
|
|
HANDLE hPrinter,
|
|
HPPD hppd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove printer forms to the forms database
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Handle to printer
|
|
hppd - Handle to PPD object
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
PMEDIAOPTION pMediaOption;
|
|
PFORM_INFO_1 pFormsDB;
|
|
WCHAR wcbuf[CCHFORMNAME];
|
|
DWORD formFlag, type, index, count;
|
|
|
|
//
|
|
// Check if we added any printer forms previously
|
|
//
|
|
|
|
if (GetPrinterData(hPrinter,
|
|
STDSTR_FORMS_ADDED,
|
|
&type,
|
|
(PBYTE) &formFlag,
|
|
sizeof(formFlag),
|
|
&count) != ERROR_SUCCESS)
|
|
{
|
|
formFlag = 0;
|
|
}
|
|
|
|
//
|
|
// Ask the spooler for a list of forms in the system
|
|
//
|
|
|
|
if (!hppd->pPageSizes || !(pFormsDB = GetDatabaseForms(hPrinter, &count)))
|
|
return;
|
|
|
|
//
|
|
// We have work to do if the following conditions are met
|
|
// formFlag > 0 and there are user forms
|
|
//
|
|
|
|
for (index=0; index < count; index++) {
|
|
|
|
if (pFormsDB[index].Flags == FORM_USER)
|
|
break;
|
|
}
|
|
|
|
if (formFlag > 0 && index < count) {
|
|
|
|
//
|
|
// Go through each printer form
|
|
//
|
|
|
|
for (pMediaOption = (PMEDIAOPTION) hppd->pPageSizes->pUiOptions;
|
|
pMediaOption != NULL;
|
|
pMediaOption = pMediaOption->pNext)
|
|
{
|
|
CopyStr2Unicode(wcbuf, GetXlatedName(pMediaOption), CCHFORMNAME);
|
|
|
|
//
|
|
// For each spooler form
|
|
//
|
|
|
|
for (index=0; index < count; index++) {
|
|
|
|
//
|
|
// Check if it's added by us for this printer
|
|
//
|
|
|
|
if (pFormsDB[index].Flags == FORM_USER &&
|
|
wcscmp(pFormsDB[index].pName, wcbuf) == EQUAL_STRING)
|
|
{
|
|
formFlag = 0;
|
|
DeleteForm(hPrinter, pFormsDB[index].pName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (formFlag == 0) {
|
|
|
|
//
|
|
// Indicate the forms have been removed
|
|
//
|
|
|
|
Warning(("Existing printer forms removed ...\n"));
|
|
|
|
SetPrinterData(hPrinter,
|
|
STDSTR_FORMS_ADDED,
|
|
REG_DWORD,
|
|
(PBYTE) &formFlag,
|
|
sizeof(formFlag));
|
|
|
|
//
|
|
// Take this chance to add printer specific forms (with new flag)
|
|
//
|
|
|
|
AddPrinterForms(hPrinter, hppd);
|
|
}
|
|
}
|
|
|
|
MEMFREE(pFormsDB);
|
|
}
|
|
|
|
|
|
|
|
PUIDATA
|
|
FillUiData(
|
|
HANDLE hPrinter,
|
|
PDEVMODE pdmInput
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill in the UIDATA structure
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Handle to the printer
|
|
pdmInput - Pointer to input devmode, NULL if there is none.
|
|
|
|
Return Value:
|
|
|
|
Pointer to UIDATA structure, NULL if error.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUIDATA pUiData;
|
|
HHEAP hheap;
|
|
DWORD cbNeeded;
|
|
LOGFORM logForm;
|
|
PDEVMODE pdm;
|
|
PPRINTERDATA pPrinterData;
|
|
PRINTER_INFO_2 *pPrinterInfo;
|
|
|
|
//
|
|
// Create a heap to manage memory
|
|
//
|
|
|
|
if ((hheap = HEAPCREATE()) == NULL)
|
|
return NULL;
|
|
|
|
//
|
|
// Allocate memory to hold UIDATA
|
|
//
|
|
|
|
pUiData = HEAPALLOC(hheap, sizeof(UIDATA));
|
|
|
|
if (pUiData == NULL) {
|
|
|
|
HEAPDESTROY(hheap);
|
|
return NULL;
|
|
}
|
|
|
|
memset(pUiData, 0, sizeof(UIDATA));
|
|
pUiData->hPrinter = hPrinter;
|
|
pUiData->hheap = hheap;
|
|
pUiData->startSign = pUiData->endSign = pUiData;
|
|
|
|
//
|
|
// Load printer PPD file
|
|
//
|
|
|
|
if ((pUiData->hppd = LoadPpdFile(hPrinter, TRUE)) == NULL) {
|
|
|
|
HEAPDESTROY(hheap);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Get printer info from the spooler
|
|
//
|
|
|
|
if (!(pPrinterInfo = MyGetPrinter(hPrinter, 2)) ||
|
|
!(pUiData->pDriverName =
|
|
HEAPALLOC(hheap, sizeof(WCHAR) * (wcslen(pPrinterInfo->pDriverName) + 1))))
|
|
{
|
|
UnloadPpdFile(pUiData->hppd);
|
|
HEAPDESTROY(hheap);
|
|
return NULL;
|
|
}
|
|
|
|
wcscpy(pUiData->pDriverName, pPrinterInfo->pDriverName);
|
|
|
|
//
|
|
// Combine input devmode with driver and system defaults
|
|
// Start with driver defaults
|
|
//
|
|
|
|
pdm = (PDEVMODE) &pUiData->devmode;
|
|
SetDefaultDevMode(pdm, pPrinterInfo->pDriverName, pUiData->hppd, IsMetricCountry());
|
|
|
|
//
|
|
// Merge with system defaults and input devmode
|
|
//
|
|
|
|
ValidateSetDevMode(pdm, pPrinterInfo->pDevMode, pUiData->hppd);
|
|
ValidateSetDevMode(pdm, pdmInput, pUiData->hppd);
|
|
|
|
MEMFREE(pPrinterInfo);
|
|
|
|
//
|
|
// Validate the form name fields
|
|
//
|
|
|
|
ValidateDevModeForm(pUiData->hPrinter, pdm, &logForm);
|
|
|
|
//
|
|
// Add printer forms to forms database
|
|
//
|
|
|
|
AddPrinterForms(hPrinter, pUiData->hppd);
|
|
|
|
//
|
|
// Get printer property data from registry
|
|
//
|
|
|
|
pPrinterData = GetPrinterProperties(hPrinter, pUiData->hppd);
|
|
|
|
if (pPrinterData == NULL) {
|
|
|
|
UnloadPpdFile(pUiData->hppd);
|
|
HEAPDESTROY(hheap);
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(&pUiData->printerData, pPrinterData, min(sizeof(PRINTERDATA), pPrinterData->wSize));
|
|
pUiData->printerData.wDriverVersion = DRIVER_VERSION;
|
|
pUiData->printerData.wSize = sizeof(PRINTERDATA);
|
|
MEMFREE(pPrinterData);
|
|
|
|
return pUiData;
|
|
}
|
|
|
|
|
|
|
|
PWSTR
|
|
GetStringFromAnsi(
|
|
PSTR ansiString,
|
|
HHEAP hheap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Make a Unicode copy of the input ANSI string
|
|
|
|
Arguments:
|
|
|
|
ansiString - Pointer to the input ANSI 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
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR pwstr;
|
|
INT length;
|
|
|
|
ASSERT(ansiString != NULL);
|
|
length = strlen(ansiString) + 1;
|
|
|
|
if (pwstr = HEAPALLOC(hheap, length * sizeof(WCHAR)))
|
|
CopyStr2Unicode(pwstr, ansiString, length);
|
|
|
|
return pwstr;
|
|
}
|
|
|
|
|
|
|
|
PWSTR
|
|
GetStringFromUnicode(
|
|
PWSTR unicodeString,
|
|
HHEAP hheap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Duplicate a Unicode string
|
|
|
|
Arguments:
|
|
|
|
unicodeString - 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
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR pwstr;
|
|
INT length;
|
|
|
|
ASSERT(unicodeString != NULL);
|
|
length = wcslen(unicodeString) + 1;
|
|
|
|
if ((pwstr = HEAPALLOC(hheap, length * sizeof(WCHAR))) != NULL) {
|
|
wcscpy(pwstr, unicodeString);
|
|
} else {
|
|
DBGERRMSG("HEAPALLOC");
|
|
}
|
|
|
|
return pwstr;
|
|
}
|
|
|
|
|
|
|
|
PWSTR
|
|
GetHelpFileName(
|
|
HANDLE hPrinter,
|
|
HHEAP hheap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return a string which contains the driver help filename
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Handle to the printer
|
|
hheap - Handle to a heap from which to allocate memory
|
|
|
|
Return Value:
|
|
|
|
Pointer to the driver help filename
|
|
NULL if error
|
|
|
|
--*/
|
|
|
|
{
|
|
static TCHAR FileName[] = TEXT("\\pscript.hlp");
|
|
PDRIVER_INFO_3 pDriverInfo3 = NULL;
|
|
LPTSTR pHelpFile = NULL;
|
|
DWORD cb;
|
|
|
|
//
|
|
// Attempt to get help file name using the new DRIVER_INFO_3
|
|
//
|
|
|
|
if (pDriverInfo3 = MyGetPrinterDriver(hPrinter, 3)) {
|
|
|
|
if (pDriverInfo3->pHelpFile)
|
|
pHelpFile = GetStringFromUnicode(pDriverInfo3->pHelpFile, hheap);
|
|
|
|
MEMFREE(pDriverInfo3);
|
|
}
|
|
|
|
if (pHelpFile)
|
|
return pHelpFile;
|
|
|
|
//
|
|
// If DRIVER_INFO_3 isn't supported, get help file name the old fashion way
|
|
//
|
|
|
|
if (!GetPrinterDriverDirectory(NULL, NULL, 1, NULL, 0, &cb) &&
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
|
|
(pHelpFile = HEAPALLOC(hheap, cb + sizeof(FileName))) &&
|
|
GetPrinterDriverDirectory(NULL, NULL, 1, (LPBYTE) pHelpFile, cb, &cb))
|
|
{
|
|
_tcscat(pHelpFile, FileName);
|
|
return pHelpFile;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
PCOMPROPSHEETUI
|
|
PrepareDataForCommonUi(
|
|
PUIDATA pUiData,
|
|
PDLGPAGE pDlgPage,
|
|
PACKPROPITEMPROC pPackItemProc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate memory and partially fill out the data structures
|
|
required to call common UI routine.
|
|
|
|
Arguments:
|
|
|
|
pUiData - Pointer to our UIDATA structure
|
|
pDlgPage - Pointer to dialog pages
|
|
pPackItemProc - Callback function to fill out OPTITEM and OPTTYPE array
|
|
|
|
Return Value:
|
|
|
|
Pointer to a COMPROPSHEETUI structure, NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PCOMPROPSHEETUI pCompstui;
|
|
PACKINFO packInfo;
|
|
PFORM_INFO_1 pForms;
|
|
DWORD cForms;
|
|
DWORD count;
|
|
HHEAP hheap = pUiData->hheap;
|
|
|
|
//
|
|
// Get a list of forms in the forms database
|
|
//
|
|
|
|
pForms = GetDatabaseForms(pUiData->hPrinter, &cForms);
|
|
|
|
if (pForms == NULL || cForms == 0)
|
|
return NULL;
|
|
|
|
//
|
|
// Enumerate form names supported on the printer
|
|
//
|
|
|
|
count = PsEnumPaperSizes(pUiData->hppd, pForms, cForms, NULL, NULL, NULL, NULL);
|
|
|
|
if (count != GDI_ERROR) {
|
|
|
|
pUiData->cFormNames = count;
|
|
|
|
pUiData->pFormNames = HEAPALLOC(hheap, count * sizeof(WCHAR) * CCHPAPERNAME);
|
|
pUiData->pPapers = HEAPALLOC(hheap, count * sizeof(WORD));
|
|
pUiData->pPaperFeatures = HEAPALLOC(hheap, count * sizeof(WORD));
|
|
}
|
|
|
|
if (!pUiData->pFormNames || !pUiData->pPapers || !pUiData->pPaperFeatures) {
|
|
|
|
MEMFREE(pForms);
|
|
return NULL;
|
|
}
|
|
|
|
PsEnumPaperSizes(pUiData->hppd,
|
|
pForms,
|
|
cForms,
|
|
pUiData->pFormNames,
|
|
pUiData->pPapers,
|
|
NULL,
|
|
pUiData->pPaperFeatures);
|
|
MEMFREE(pForms);
|
|
|
|
//
|
|
// Enumerate input bin names supported on the printer
|
|
//
|
|
|
|
count = PsEnumBinNames(NULL, pUiData->hppd);
|
|
|
|
if (count != GDI_ERROR) {
|
|
|
|
pUiData->cBinNames = count;
|
|
pUiData->pBinNames = HEAPALLOC(hheap, count * sizeof(WCHAR) * CCHBINNAME);
|
|
}
|
|
|
|
if (! pUiData->pBinNames)
|
|
return NULL;
|
|
PsEnumBinNames(pUiData->pBinNames, pUiData->hppd);
|
|
|
|
//
|
|
// Enumerate resolutions supported on the printer
|
|
//
|
|
|
|
count = PsEnumResolutions(NULL, pUiData->hppd);
|
|
|
|
if (count != GDI_ERROR) {
|
|
|
|
pUiData->cResolutions = count;
|
|
pUiData->pResolutions = HEAPALLOC(hheap, count * sizeof(LONG) * 2);
|
|
}
|
|
|
|
if (! pUiData->pResolutions)
|
|
return NULL;
|
|
PsEnumResolutions(pUiData->pResolutions, pUiData->hppd);
|
|
|
|
//
|
|
// Allocate memory to hold various data structures
|
|
//
|
|
|
|
if (! (pCompstui = HEAPALLOC(hheap, sizeof(COMPROPSHEETUI))))
|
|
return NULL;
|
|
|
|
memset(pCompstui, 0, sizeof(COMPROPSHEETUI));
|
|
|
|
//
|
|
// Initialize COMPROPSHEETUI structure
|
|
//
|
|
|
|
pCompstui->cbSize = sizeof(COMPROPSHEETUI);
|
|
pCompstui->UserData = (DWORD) pUiData;
|
|
pCompstui->pDlgPage = pDlgPage;
|
|
pCompstui->cDlgPage = 0;
|
|
|
|
pCompstui->hInstCaller = ghInstance;
|
|
pCompstui->pCallerName = (PWSTR) IDS_POSTSCRIPT;
|
|
pCompstui->pOptItemName = pUiData->pDriverName;
|
|
pCompstui->CallerVersion = DRIVER_VERSION;
|
|
pCompstui->OptItemVersion = 0;
|
|
|
|
pCompstui->IconID = IDI_CPSUI_POSTSCRIPT;
|
|
if (HasPermission(pUiData))
|
|
pCompstui->Flags = CPSUIF_UPDATE_PERMISSION;
|
|
|
|
pCompstui->pHelpFile = GetHelpFileName(pUiData->hPrinter, hheap);
|
|
|
|
//
|
|
// Count the number of OPTITEM's and OPTTYPE's
|
|
//
|
|
|
|
memset(&packInfo, 0, sizeof(packInfo));
|
|
packInfo.pUiData = pUiData;
|
|
if (! pPackItemProc(&packInfo))
|
|
return NULL;
|
|
|
|
//
|
|
// Allocate memory to hold OPTITEM's and OPTTYPE's
|
|
//
|
|
|
|
ASSERT(packInfo.cOptItem > 0 && packInfo.cOptType > 0);
|
|
|
|
packInfo.pOptItem = HEAPALLOC(hheap, sizeof(OPTITEM) * packInfo.cOptItem);
|
|
packInfo.pOptType = HEAPALLOC(hheap, sizeof(OPTTYPE) * packInfo.cOptType);
|
|
|
|
if (!packInfo.pOptItem || !packInfo.pOptType)
|
|
return NULL;
|
|
|
|
//
|
|
// Pack the document properties information into OPTITEM array
|
|
//
|
|
|
|
memset(packInfo.pOptItem, 0, sizeof(OPTITEM) * packInfo.cOptItem);
|
|
memset(packInfo.pOptType, 0, sizeof(OPTTYPE) * packInfo.cOptType);
|
|
packInfo.cOptItem = packInfo.cOptType = 0;
|
|
pCompstui->pOptItem = packInfo.pOptItem;
|
|
|
|
if (! pPackItemProc(&packInfo))
|
|
return NULL;
|
|
|
|
pCompstui->cOptItem = packInfo.cOptItem;
|
|
return pCompstui;
|
|
}
|
|
|
|
|
|
|
|
POPTPARAM
|
|
FillOutOptType(
|
|
POPTTYPE popttype,
|
|
WORD type,
|
|
WORD cParams,
|
|
HHEAP hheap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill out an OPTTYPE structure
|
|
|
|
Arguments:
|
|
|
|
popttype - Pointer to OPTTYPE structure to be filled out
|
|
type - Value for OPTTYPE.Type field
|
|
cParams - Number of OPTPARAM's
|
|
hheap - Handle to a heap from which to allocate
|
|
|
|
Return Value:
|
|
|
|
Pointer to OPTPARAM array if successful, NULL otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
POPTPARAM pOptParam;
|
|
|
|
popttype->cbSize = sizeof(OPTTYPE);
|
|
popttype->Count = cParams;
|
|
popttype->Type = (BYTE) type;
|
|
|
|
pOptParam = HEAPALLOC(hheap, sizeof(OPTPARAM) * cParams);
|
|
if (pOptParam != NULL) {
|
|
popttype->pOptParam = pOptParam;
|
|
memset(pOptParam, 0, sizeof(OPTPARAM) * cParams);
|
|
} else {
|
|
DBGERRMSG("HEAPALLOC");
|
|
}
|
|
|
|
return pOptParam;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
PackOptItemTemplate(
|
|
PPACKINFO pPackInfo,
|
|
PWORD pItemInfo,
|
|
DWORD selection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill out an OPTITEM and an OPTTYPE structure using a template
|
|
|
|
Arguments:
|
|
|
|
pPackInfo - Pointer to PACKINFO structure
|
|
pItemInfo - Pointer to item template
|
|
selection - Current item selection
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
[Note:]
|
|
|
|
The item template is a variable size WORD array:
|
|
0: String resource ID of the item title
|
|
1: Item level in the tree view (TVITEM_LEVELx)
|
|
2: Public devmode field ID (DMPUB_xxx)
|
|
3: User data
|
|
4: Help index
|
|
5: Number of OPTPARAMs for this item
|
|
6: Item type (TVOT_xxx)
|
|
Three words for each OPTPARAM:
|
|
String resource ID for parameter data
|
|
Icon resource ID
|
|
Last word must be ITEM_INFO_SIGNATURE
|
|
|
|
Both OPTITEM and OPTTYPE structures are assumed to be zero-initialized.
|
|
|
|
--*/
|
|
|
|
{
|
|
POPTITEM pOptItem;
|
|
POPTPARAM pOptParam;
|
|
WORD cOptParam;
|
|
|
|
if ((pOptItem = pPackInfo->pOptItem) != NULL) {
|
|
|
|
FILLOPTITEM(pOptItem,
|
|
pPackInfo->pOptType,
|
|
pItemInfo[0],
|
|
selection,
|
|
(BYTE) pItemInfo[1],
|
|
(BYTE) pItemInfo[2],
|
|
pItemInfo[3],
|
|
pItemInfo[4]);
|
|
|
|
cOptParam = pItemInfo[5];
|
|
pOptParam = FillOutOptType(
|
|
pPackInfo->pOptType, pItemInfo[6], cOptParam,
|
|
pPackInfo->pUiData->hheap);
|
|
if (pOptParam == NULL)
|
|
return FALSE;
|
|
|
|
pItemInfo += 7;
|
|
while (cOptParam--) {
|
|
|
|
pOptParam->cbSize = sizeof(OPTPARAM);
|
|
pOptParam->pData = (PWSTR) *pItemInfo++;
|
|
pOptParam->IconID = *pItemInfo++;
|
|
pOptParam++;
|
|
}
|
|
|
|
ASSERT(*pItemInfo == ITEM_INFO_SIGNATURE);
|
|
|
|
pPackInfo->pOptItem++;
|
|
pPackInfo->pOptType++;
|
|
}
|
|
|
|
pPackInfo->cOptItem++;
|
|
pPackInfo->cOptType++;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
PackOptItemGroupHeader(
|
|
PPACKINFO pPackInfo,
|
|
WORD titleId,
|
|
WORD iconId,
|
|
WORD helpIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill out a OPTITEM to be used as a header for a group of items
|
|
|
|
Arguments:
|
|
|
|
pPackInfo - Pointer to a PACKINFO structure
|
|
titleId - String resource ID for the item title
|
|
iconId - Icon resource ID
|
|
helpIndex - Help index
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
if (pPackInfo->pOptItem) {
|
|
|
|
pPackInfo->pOptItem->cbSize = sizeof(OPTITEM);
|
|
pPackInfo->pOptItem->pOptType = NULL;
|
|
pPackInfo->pOptItem->pName = (PWSTR) titleId;
|
|
pPackInfo->pOptItem->Level = TVITEM_LEVEL1;
|
|
pPackInfo->pOptItem->DMPubID = DMPUB_NONE;
|
|
pPackInfo->pOptItem->Sel = iconId;
|
|
pPackInfo->pOptItem->HelpIndex = helpIndex;
|
|
pPackInfo->pOptItem++;
|
|
}
|
|
|
|
pPackInfo->cOptItem++;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
PackPrinterFeatureItems(
|
|
PPACKINFO pPackInfo,
|
|
PUIGROUP pUiGroups,
|
|
WORD cFeatures,
|
|
PBYTE pOptions,
|
|
BOOL bInstallable,
|
|
HHEAP hheap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pack printer features into treeview items for use by common UI DLL
|
|
|
|
Arguments:
|
|
|
|
pPackInfo - Pointer to a PACKINFO structure
|
|
pUiGroups - Pointer to a list of UIGROUP objects
|
|
cFeatures - Number of features to be packed
|
|
pOptions - Pointer to a BYTE array - current selections
|
|
bInstallable - Processing installable options?
|
|
hheap - Handle to a heap from which to allocate memory
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUIOPTION pUiOptions;
|
|
POPTPARAM pOptParam;
|
|
BYTE selection;
|
|
WORD cOptions;
|
|
PWSTR pwstr;
|
|
WORD helpIndex, iconId;
|
|
|
|
// Figure out the correct help index and icon ID
|
|
// depending on whether we're dealing with installable
|
|
// options or document-sticky printer features
|
|
|
|
if (bInstallable) {
|
|
|
|
helpIndex = HELP_INDEX_INSTALLABLE_OPTIONS;
|
|
iconId = IDI_CPSUI_INSTALLABLE_OPTION;
|
|
|
|
} else {
|
|
|
|
helpIndex = HELP_INDEX_PRINTER_FEATURES;
|
|
iconId = IDI_CPSUI_PRINTER_FEATURE;
|
|
}
|
|
|
|
for ( ; cFeatures--; pUiGroups = pUiGroups->pNext, pOptions++) {
|
|
|
|
ASSERT(pUiGroups != NULL && pUiGroups->bInstallable == bInstallable);
|
|
|
|
// Weed out those features which correspond to public devmode
|
|
// fields. Also, ignore features which don't have any options.
|
|
|
|
if ((! bInstallable && PublicGroupIndex(pUiGroups->uigrpIndex)) ||
|
|
(cOptions = (WORD) UIGROUP_CountOptions(pUiGroups)) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (pPackInfo->pOptItem) {
|
|
|
|
// Get feature name string
|
|
|
|
pwstr = GetStringFromAnsi(GetXlatedName(pUiGroups), hheap);
|
|
if (pwstr == NULL)
|
|
return FALSE;
|
|
|
|
// Find out the current selection. For document-sticky
|
|
// features, we always insert "Printer Default" as the
|
|
// very first choice. This is represented by OPTION_INDEX_ANY
|
|
// in the options array.
|
|
|
|
selection = *pOptions;
|
|
|
|
if (! bInstallable) {
|
|
|
|
selection = (selection >= cOptions) ? 0 : selection+1;
|
|
cOptions++;
|
|
}
|
|
|
|
FILLOPTITEM(pPackInfo->pOptItem,
|
|
pPackInfo->pOptType,
|
|
pwstr,
|
|
selection,
|
|
TVITEM_LEVEL2,
|
|
DMPUB_NONE,
|
|
pUiGroups,
|
|
helpIndex);
|
|
|
|
pOptParam =
|
|
FillOutOptType(
|
|
pPackInfo->pOptType, TVOT_LISTBOX, cOptions, hheap);
|
|
|
|
if (pOptParam == NULL)
|
|
return FALSE;
|
|
|
|
if (! bInstallable) {
|
|
|
|
pOptParam->cbSize = sizeof(OPTPARAM);
|
|
pOptParam->pData = (PVOID) IDS_PRINTER_DEFAULT;
|
|
pOptParam->IconID = IDI_CPSUI_EMPTY;
|
|
|
|
cOptions--;
|
|
pOptParam++;
|
|
}
|
|
|
|
pUiOptions = pUiGroups->pUiOptions;
|
|
|
|
while (cOptions--) {
|
|
|
|
pwstr = GetStringFromAnsi(GetXlatedName(pUiOptions), hheap);
|
|
if (pwstr == NULL)
|
|
return FALSE;
|
|
|
|
pOptParam->cbSize = sizeof(OPTPARAM);
|
|
pOptParam->pData = pwstr;
|
|
pOptParam->IconID = iconId;
|
|
|
|
#if _NOT_USED_
|
|
|
|
// !!! Don't display document-sticky options that has
|
|
// no invocation string (because that's equivalent to
|
|
// "Printer Default").
|
|
|
|
if (! bInstallable &&
|
|
EmptyInvocationStr(pUiOptions->pInvocation))
|
|
{
|
|
pOptParam->Flags = OPTPF_HIDE | CONSTRAINED_FLAG;
|
|
}
|
|
|
|
#endif
|
|
|
|
pOptParam++;
|
|
pUiOptions = pUiOptions->pNext;
|
|
}
|
|
|
|
pPackInfo->pOptItem++;
|
|
pPackInfo->pOptType++;
|
|
}
|
|
|
|
pPackInfo->cOptItem++;
|
|
pPackInfo->cOptType++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Data structure used to pass parameters to "Conflicts" dialog
|
|
//
|
|
|
|
typedef struct {
|
|
|
|
PFNCOMPROPSHEET pfnComPropSheet;
|
|
HANDLE hComPropSheet;
|
|
HPPD hppd;
|
|
BOOL bFinal;
|
|
POPTITEM pOptItem;
|
|
|
|
} DLGPARAM, *PDLGPARAM;
|
|
|
|
LPTSTR
|
|
GetMsgStr(
|
|
LPTSTR wcbuf,
|
|
DWORD dwId,
|
|
PDLGPARAM pDlgParam
|
|
)
|
|
|
|
{
|
|
//
|
|
// If pName is already a pointer, return it to the caller
|
|
//
|
|
|
|
if (dwId >= 0x10000)
|
|
return (LPTSTR) dwId;
|
|
|
|
//
|
|
// If pName is a string resource ID, check if it's our own
|
|
// or if it belong to common UI library.
|
|
//
|
|
|
|
wcbuf[0] = NUL;
|
|
|
|
if (dwId < IDS_CPSUI_STRID_FIRST)
|
|
LoadString(ghInstance, (INT) dwId, wcbuf, MAX_OPTION_NAME);
|
|
else
|
|
pDlgParam->pfnComPropSheet(pDlgParam->hComPropSheet,
|
|
CPSFUNC_LOAD_CPSUI_STRING,
|
|
(LPARAM) wcbuf,
|
|
MAKELONG(MAX_OPTION_NAME, dwId));
|
|
return wcbuf;
|
|
}
|
|
|
|
BOOL CALLBACK
|
|
ConflictsDlgProc(
|
|
HWND hDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dialog procedure for handle "Conflicts" dialog
|
|
|
|
Arguments:
|
|
|
|
hDlg - Handle to dialog window
|
|
uMsg - Message
|
|
wParam, lParam - Parameters
|
|
|
|
Return Value:
|
|
|
|
TRUE or FALSE depending on whether message is processed
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (uMsg) {
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
PDLGPARAM pDlgParam;
|
|
POPTITEM pOptItem;
|
|
POPTPARAM pOptParam;
|
|
PUIGROUP pUiGroup;
|
|
PUIOPTION pUiOption;
|
|
WCHAR wcbuf[MAX_OPTION_NAME];
|
|
WORD feature, selection;
|
|
|
|
pDlgParam = (PDLGPARAM) lParam;
|
|
ASSERT(pDlgParam != NULL);
|
|
|
|
pOptItem = pDlgParam->pOptItem;
|
|
pOptParam = &pOptItem->pOptType->pOptParam[pOptItem->Sel];
|
|
|
|
// Display the current feature and selection
|
|
|
|
SetDlgItemText(hDlg, IDC_FEATURE1, GetMsgStr(wcbuf, (INT) pOptItem->pName, pDlgParam));
|
|
SetDlgItemText(hDlg, IDC_OPTION1, GetMsgStr(wcbuf, (INT) pOptParam->pData, pDlgParam));
|
|
|
|
// Display the conflicting feature and selection
|
|
|
|
EXTRACT_CONSTRAINT_PARAM(pOptParam->lParam, feature, selection);
|
|
PpdFindFeatureSelection(pDlgParam->hppd, feature, selection, &pUiGroup, &pUiOption);
|
|
|
|
if (pUiGroup) {
|
|
|
|
CopyStr2Unicode(wcbuf, GetXlatedName(pUiGroup), MAX_OPTION_NAME);
|
|
SetDlgItemText(hDlg, IDC_FEATURE2, wcbuf);
|
|
}
|
|
|
|
if (pUiOption) {
|
|
|
|
CopyStr2Unicode(wcbuf, GetXlatedName(pUiOption), MAX_OPTION_NAME);
|
|
SetDlgItemText(hDlg, IDC_OPTION2, wcbuf);
|
|
}
|
|
|
|
// If user is trying to exit the dialog, we need to:
|
|
//
|
|
// 1. Hide Resolve button
|
|
// 2. Hide Ignore button if necessary
|
|
// 3. Change the static text message in the dialog accordingly
|
|
|
|
if (pDlgParam->bFinal) {
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_RESOLVE), SW_HIDE);
|
|
SetDlgItemText(hDlg, IDC_RESOLVEMSG, TEXT(""));
|
|
|
|
if (pOptParam->lParam & HARD_CONSTRAINT) {
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_IGNORE), SW_HIDE);
|
|
SetDlgItemText(hDlg, IDC_IGNOREMSG, TEXT(""));
|
|
|
|
} else {
|
|
|
|
SetDlgItemText(hDlg,
|
|
IDC_IGNOREMSG,
|
|
GetMsgStr(wcbuf, IDS_IGNORE_CONFLICT, pDlgParam));
|
|
}
|
|
|
|
SetDlgItemText(hDlg, IDC_CANCELMSG, GetMsgStr(wcbuf, IDS_CANCEL_CONFLICT, pDlgParam));
|
|
}
|
|
|
|
ShowWindow(hDlg, SW_SHOW);
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDCANCEL:
|
|
case IDC_IGNORE:
|
|
case IDC_RESOLVE:
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
CheckConstraintsDlg(
|
|
PUIDATA pUiData,
|
|
POPTITEM pOptItem,
|
|
WORD cOptItem,
|
|
BOOL bFinal
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the user chose any constrained selection
|
|
|
|
Arguments:
|
|
|
|
pUiData - Pointer to our UIDATA structure
|
|
pOptItem - Pointer to an array of OPTITEMs
|
|
cOptItem - Number of items to be checked
|
|
bFinal - Whether this is called when user tries to exit the dialog
|
|
|
|
Return Value:
|
|
|
|
CONFLICT_NONE - no conflicts
|
|
CONFLICT_RESOLVE - click RESOLVE to automatically resolve conflicts
|
|
CONFLICT_CANCEL - click CANCEL to back out of changes
|
|
CONFLICT_IGNORE - click IGNORE to ignore conflicts
|
|
|
|
--*/
|
|
|
|
{
|
|
DLGPARAM dlgParam;
|
|
INT result = CONFLICT_NONE;
|
|
|
|
dlgParam.pfnComPropSheet = pUiData->pfnComPropSheet;
|
|
dlgParam.hComPropSheet = pUiData->hComPropSheet;
|
|
dlgParam.hppd = pUiData->hppd;
|
|
dlgParam.bFinal = bFinal;
|
|
|
|
for ( ; cOptItem-- && result != CONFLICT_CANCEL; pOptItem++) {
|
|
|
|
// If user has clicked IGNORE before, then don't bother
|
|
// checking anymore until he tries to exit the dialog.
|
|
|
|
if (pUiData->bIgnoreConflict && !bFinal)
|
|
break;
|
|
|
|
// If there is a conflict, then display a warning message
|
|
|
|
ASSERT(pOptItem->pOptType->Type == TVOT_LISTBOX);
|
|
if (IS_CONSTRAINED(pOptItem, pOptItem->Sel)) {
|
|
|
|
dlgParam.pOptItem = pOptItem;
|
|
|
|
result = DialogBoxParam(ghInstance,
|
|
MAKEINTRESOURCE(IDD_CONFLICTS),
|
|
pUiData->hDlg,
|
|
ConflictsDlgProc,
|
|
(LPARAM) &dlgParam);
|
|
|
|
// Automatically resolve conflicts. We're being very
|
|
// simple-minded here, i.e. picking the first selection
|
|
// that's not constrained.
|
|
|
|
if (result == CONFLICT_RESOLVE) {
|
|
|
|
INT index, count;
|
|
|
|
count = pOptItem->pOptType->Count;
|
|
index = 0;
|
|
|
|
while (index < count && IS_CONSTRAINED(pOptItem, index))
|
|
index++;
|
|
|
|
if (index < count) {
|
|
|
|
pOptItem->Sel = index;
|
|
pOptItem->Flags |= OPTIF_CHANGED;
|
|
|
|
} else {
|
|
|
|
DBGMSG(DBG_LEVEL_WARNING,
|
|
"Couldn't automatically resolve conflicts.\n");
|
|
}
|
|
|
|
} else if (result == CONFLICT_IGNORE) {
|
|
|
|
pUiData->bIgnoreConflict = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
MarkSelectionConstrained(
|
|
POPTITEM pOptItem,
|
|
WORD selection,
|
|
LONG lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indicate whether a selection is constrained or not
|
|
|
|
Arguments:
|
|
|
|
pOptItem - Pointer to the OPTITEM in question
|
|
selection - Which selection are we interested in?
|
|
bConflict - Whether the selection is constrained or not
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
POPTPARAM pOptParam = & pOptItem->pOptType->pOptParam[selection];
|
|
|
|
if (lParam && ! (pOptParam->Flags & CONSTRAINED_FLAG)) {
|
|
|
|
pOptParam->Flags |= CONSTRAINED_FLAG;
|
|
pOptItem->Flags |= OPTIF_CHANGED;
|
|
|
|
} else if (!lParam && (pOptParam->Flags & CONSTRAINED_FLAG)) {
|
|
|
|
pOptParam->Flags &= ~CONSTRAINED_FLAG;
|
|
pOptItem->Flags |= OPTIF_CHANGED;
|
|
}
|
|
|
|
pOptParam->lParam = lParam;
|
|
}
|
|
|
|
|
|
|
|
WORD
|
|
FindFormNameIndex(
|
|
PUIDATA pUiData,
|
|
PWSTR pFormName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a formname, find its index in the list of supported forms
|
|
|
|
Arguments:
|
|
|
|
pUiData - Pointer to our UIDATA structure
|
|
pFormName - Formname in question
|
|
|
|
Return Value:
|
|
|
|
Index of the specified formname in the list
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD index;
|
|
PWSTR pName;
|
|
DWORD cbNeeded;
|
|
PFORM_INFO_1 pFormInfo;
|
|
|
|
// Check if the name appears in the list
|
|
|
|
for (index = 0, pName = pUiData->pFormNames;
|
|
index < pUiData->cFormNames;
|
|
index ++, pName += CCHPAPERNAME)
|
|
{
|
|
if (wcscmp(pFormName, pName) == EQUAL_STRING)
|
|
return index;
|
|
}
|
|
|
|
// If the name is not in the list, try to match
|
|
// the form to a printer page size
|
|
|
|
if (!GetForm(pUiData->hPrinter, pFormName, 1, NULL, 0, &cbNeeded) &&
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
|
|
(pFormInfo = MEMALLOC(cbNeeded)))
|
|
{
|
|
PRINTERFORM printerForm;
|
|
|
|
if (GetForm(pUiData->hPrinter, pFormName, 1, (PBYTE) pFormInfo, cbNeeded, &cbNeeded) &&
|
|
FormSupportedOnPrinter(pUiData->hppd, pFormInfo, &printerForm, FALSE) &&
|
|
!IsCustomPrinterForm(&printerForm))
|
|
{
|
|
PMEDIAOPTION pmo;
|
|
|
|
pmo = (PMEDIAOPTION)
|
|
LISTOBJ_FindIndexed((PLISTOBJ) pUiData->hppd->pPageSizes->pUiOptions,
|
|
printerForm.featureIndex);
|
|
ASSERT(pmo != NULL);
|
|
|
|
pFormName = printerForm.FormName;
|
|
CopyStr2Unicode(pFormName, GetXlatedName(pmo), CCHFORMNAME);
|
|
|
|
for (index = 0, pName = pUiData->pFormNames;
|
|
index < pUiData->cFormNames;
|
|
index ++, pName += CCHPAPERNAME)
|
|
{
|
|
if (wcscmp(pFormName, pName) == EQUAL_STRING) {
|
|
|
|
MEMFREE(pFormInfo);
|
|
return index;
|
|
}
|
|
}
|
|
}
|
|
|
|
MEMFREE(pFormInfo);
|
|
}
|
|
|
|
// The specified form is not supported on the printer.
|
|
// Select the first available form.
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
CallCompstui(
|
|
HWND hwndOwner,
|
|
PFNPROPSHEETUI pfnPropSheetUI,
|
|
LPARAM lParam,
|
|
PDWORD pResult
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calling common UI DLL entry point dynamically
|
|
|
|
Arguments:
|
|
|
|
hwndOwner, pfnPropSheetUI, lParam, pResult - Parameters passed to common UI DLL
|
|
|
|
Return Value:
|
|
|
|
Return value from common UI library
|
|
|
|
--*/
|
|
|
|
{
|
|
HINSTANCE hInstCompstui;
|
|
FARPROC pProc;
|
|
LONG Result = ERR_CPSUI_GETLASTERROR;
|
|
|
|
//
|
|
// Only need to call the ANSI version of LoadLibrary
|
|
//
|
|
|
|
static const CHAR szCompstui[] = "compstui.dll";
|
|
static const CHAR szCommonPropSheetUI[] = "CommonPropertySheetUIW";
|
|
|
|
if ((hInstCompstui = LoadLibraryA(szCompstui)) &&
|
|
(pProc = GetProcAddress(hInstCompstui, szCommonPropSheetUI)))
|
|
{
|
|
Result = (*pProc)(hwndOwner, pfnPropSheetUI, lParam, pResult);
|
|
}
|
|
|
|
if (hInstCompstui)
|
|
FreeLibrary(hInstCompstui);
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
OptItemSelectionsChanged(
|
|
POPTITEM pItems,
|
|
WORD cItems
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if any of the OPTITEM's was changed by the user
|
|
|
|
Arguments:
|
|
|
|
pItems - Pointer to an array of OPTITEM's
|
|
cItems - Number of OPTITEM's
|
|
|
|
Return Value:
|
|
|
|
TRUE if anything was changed, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
while (cItems--) {
|
|
|
|
if (pItems->Flags & OPTIF_CHANGEONCE)
|
|
return TRUE;
|
|
|
|
pItems++;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|