1986 lines
47 KiB
C
1986 lines
47 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
commonui.c
|
||
|
||
Abstract:
|
||
|
||
This file contains all the functions related to preparing data for
|
||
CPSUI. This includes packing data items for printer property sheets and
|
||
document property sheets.
|
||
|
||
Environment:
|
||
|
||
Win32 subsystem, DriverUI module, user mode
|
||
|
||
Revision History:
|
||
|
||
02/13/97 -davidx-
|
||
Common function to handle well-known and generic printer features.
|
||
|
||
02/10/97 -davidx-
|
||
Consistent handling of common printer info.
|
||
|
||
02/04/97 -davidx-
|
||
Reorganize driver UI to separate ps and uni DLLs.
|
||
|
||
09/12/96 -amandan-
|
||
Created it.
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
|
||
|
||
PCOMPROPSHEETUI
|
||
PPrepareDataForCommonUI(
|
||
IN OUT PUIDATA pUiData,
|
||
IN PDLGPAGE pDlgPage
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocate memory and partially fill out the data structures required
|
||
to call common UI routine. Once all information in pUiData are
|
||
initialized properly, it calls PackDocumentPropertyItems() or
|
||
PackPrinterPropertyItems() to pack the option items.
|
||
|
||
Arguments:
|
||
|
||
pUiData - Pointer to our UIDATA structure
|
||
pDlgPage - Pointer to dialog pages
|
||
|
||
Return Value:
|
||
|
||
Pointer to a COMPROPSHEETUI structure, NULL if there is an error
|
||
|
||
--*/
|
||
|
||
{
|
||
PCOMPROPSHEETUI pCompstui;
|
||
DWORD dwCount, dwIcon, dwOptItemCount, dwSize;
|
||
PCOMMONINFO pci = (PCOMMONINFO) pUiData;
|
||
HANDLE hHeap = pUiData->ci.hHeap;
|
||
BOOL (*pfnPackItemProc)(PUIDATA);
|
||
POPTITEM pOptItem;
|
||
PBYTE pUserData;
|
||
|
||
//
|
||
// Enumerate form names supported on the printer
|
||
//
|
||
|
||
dwCount = DwEnumPaperSizes(pci, NULL, NULL, NULL, NULL, UNUSED_PARAM);
|
||
|
||
if (dwCount != GDI_ERROR && dwCount != 0)
|
||
{
|
||
pUiData->dwFormNames = dwCount;
|
||
|
||
pUiData->pFormNames = HEAPALLOC(hHeap, dwCount * sizeof(WCHAR) * CCHPAPERNAME);
|
||
pUiData->pwPapers = HEAPALLOC(hHeap, dwCount * sizeof(WORD));
|
||
pUiData->pwPaperFeatures = HEAPALLOC(hHeap, dwCount * sizeof(WORD));
|
||
}
|
||
|
||
if (!pUiData->pFormNames || !pUiData->pwPapers || !pUiData->pwPaperFeatures)
|
||
return NULL;
|
||
|
||
(VOID) DwEnumPaperSizes(
|
||
pci,
|
||
pUiData->pFormNames,
|
||
pUiData->pwPapers,
|
||
NULL,
|
||
pUiData->pwPaperFeatures,
|
||
UNUSED_PARAM);
|
||
|
||
#ifdef PSCRIPT
|
||
|
||
//
|
||
// We don't need to keep information about spooler forms
|
||
// after this point. So dispose of it to free up memory.
|
||
//
|
||
|
||
MemFree(pUiData->ci.pSplForms);
|
||
pUiData->ci.pSplForms = NULL;
|
||
pUiData->ci.dwSplForms = 0;
|
||
|
||
#endif
|
||
|
||
//
|
||
// Enumerate input bin names supported on the printer
|
||
//
|
||
|
||
dwCount = DwEnumBinNames(pci, NULL);
|
||
|
||
if (dwCount != GDI_ERROR)
|
||
{
|
||
pUiData->dwBinNames = dwCount;
|
||
pUiData->pBinNames = HEAPALLOC(hHeap, dwCount * sizeof(WCHAR) * CCHBINNAME);
|
||
}
|
||
|
||
if (! pUiData->pBinNames)
|
||
return NULL;
|
||
|
||
//
|
||
// Don't need to check return here
|
||
//
|
||
|
||
DwEnumBinNames(pci, pUiData->pBinNames);
|
||
|
||
//
|
||
// 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 = (ULONG_PTR) pUiData;
|
||
pCompstui->pDlgPage = pDlgPage;
|
||
pCompstui->cDlgPage = 0;
|
||
|
||
pCompstui->hInstCaller = ghInstance;
|
||
pCompstui->pCallerName = _PwstrGetCallerName();
|
||
pCompstui->pOptItemName = pUiData->ci.pDriverInfo3->pName;
|
||
pCompstui->CallerVersion = gwDriverVersion;
|
||
pCompstui->OptItemVersion = 0;
|
||
|
||
dwIcon = pUiData->ci.pUIInfo->loPrinterIcon;
|
||
|
||
if (dwIcon && (pCompstui->IconID = HLoadIconFromResourceDLL(&pUiData->ci, dwIcon)))
|
||
pCompstui->Flags |= CPSUIF_ICONID_AS_HICON;
|
||
else
|
||
pCompstui->IconID = _DwGetPrinterIconID();
|
||
|
||
if (HASPERMISSION(pUiData))
|
||
pCompstui->Flags |= CPSUIF_UPDATE_PERMISSION;
|
||
|
||
pCompstui->Flags |= CPSUIF_ABOUT_CALLBACK;
|
||
|
||
|
||
pCompstui->pHelpFile = pUiData->ci.pDriverInfo3->pHelpFile;
|
||
|
||
//
|
||
// Call either PackDocumentPropertyItems or PackPrinterPropertyItems
|
||
// to get the number of items and types.
|
||
//
|
||
|
||
pfnPackItemProc = (pUiData->iMode == MODE_DOCUMENT_STICKY) ?
|
||
BPackDocumentPropertyItems :
|
||
BPackPrinterPropertyItems;
|
||
|
||
pUiData->dwOptItem = 0;
|
||
pUiData->pOptItem = NULL;
|
||
pUiData->dwOptType = 0;
|
||
pUiData->pOptType = NULL;
|
||
|
||
if (! pfnPackItemProc(pUiData))
|
||
{
|
||
ERR(("Error while packing OPTITEM's\n"));
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Allocate memory to hold OPTITEMs and OPTTYPEs
|
||
//
|
||
|
||
ASSERT(pUiData->dwOptItem > 0);
|
||
VERBOSE(("Number of OPTTYPE's: %d\n", pUiData->dwOptType));
|
||
VERBOSE(("Number of OPTITEM's: %d\n", pUiData->dwOptItem));
|
||
|
||
pUiData->pOptItem = HEAPALLOC(hHeap, sizeof(OPTITEM) * pUiData->dwOptItem);
|
||
pUiData->pOptType = HEAPALLOC(hHeap, sizeof(OPTTYPE) * pUiData->dwOptType);
|
||
pUserData = HEAPALLOC(hHeap, sizeof(USERDATA)* pUiData->dwOptItem);
|
||
|
||
if (!pUiData->pOptItem || !pUiData->pOptType || !pUserData)
|
||
return NULL;
|
||
|
||
//
|
||
// Initializes OPTITEM.USERDATA
|
||
//
|
||
|
||
pOptItem = pUiData->pOptItem;
|
||
dwOptItemCount = pUiData->dwOptItem;
|
||
dwSize = sizeof(USERDATA);
|
||
|
||
while (dwOptItemCount--)
|
||
{
|
||
|
||
pOptItem->UserData = (ULONG_PTR)pUserData;
|
||
|
||
SETUSERDATA_SIZE(pOptItem, dwSize);
|
||
|
||
pUserData += sizeof(USERDATA);
|
||
pOptItem++;
|
||
|
||
}
|
||
|
||
pUiData->pDrvOptItem = pUiData->pOptItem;
|
||
pCompstui->pOptItem = pUiData->pDrvOptItem;
|
||
pCompstui->cOptItem = (WORD) pUiData->dwOptItem;
|
||
|
||
pUiData->dwOptItem = pUiData->dwOptType = 0;
|
||
|
||
//
|
||
// Call either PackDocumentPropertyItems or PackPrinterPropertyItems
|
||
// to build the OPTITEMs list
|
||
//
|
||
|
||
if (! pfnPackItemProc(pUiData))
|
||
{
|
||
ERR(("Error while packing OPTITEM's\n"));
|
||
return NULL;
|
||
}
|
||
|
||
return pCompstui;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
VPackOptItemGroupHeader(
|
||
IN OUT PUIDATA pUiData,
|
||
IN DWORD dwTitleId,
|
||
IN DWORD dwIconId,
|
||
IN DWORD dwHelpIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Fill out a OPTITEM to be used as a header for a group of items
|
||
|
||
Arguments:
|
||
|
||
pUiData - Points to UIDATA structure
|
||
dwTitleId - String resource ID for the item title
|
||
dwIconId - Icon resource ID
|
||
dwHelpIndex - Help index
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
{
|
||
if (pUiData->pOptItem)
|
||
{
|
||
pUiData->pOptItem->cbSize = sizeof(OPTITEM);
|
||
pUiData->pOptItem->pOptType = NULL;
|
||
pUiData->pOptItem->pName = (PWSTR)ULongToPtr(dwTitleId);
|
||
pUiData->pOptItem->Level = TVITEM_LEVEL1;
|
||
pUiData->pOptItem->DMPubID = DMPUB_NONE;
|
||
pUiData->pOptItem->Sel = dwIconId;
|
||
//pUiData->pOptItem->UserData = 0;
|
||
pUiData->pOptItem->HelpIndex = dwHelpIndex;
|
||
pUiData->pOptItem++;
|
||
}
|
||
|
||
pUiData->dwOptItem++;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
BPackOptItemTemplate(
|
||
IN OUT PUIDATA pUiData,
|
||
IN CONST WORD pwItemInfo[],
|
||
IN DWORD dwSelection,
|
||
IN PFEATURE pFeature
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Fill out an OPTITEM and an OPTTYPE structure using a template
|
||
|
||
Arguments:
|
||
|
||
pUiData - Points to UIDATA structure
|
||
pwItemInfo - Pointer to item template
|
||
dwSelection - Current item selection
|
||
pFeature - Pointer to FEATURE
|
||
|
||
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:
|
||
Size of 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 wOptParam;
|
||
POPTTYPE pOptType = pUiData->pOptType;
|
||
|
||
|
||
if ((pOptItem = pUiData->pOptItem) != NULL)
|
||
{
|
||
FILLOPTITEM(pOptItem,
|
||
pUiData->pOptType,
|
||
ULongToPtr(pwItemInfo[0]),
|
||
ULongToPtr(dwSelection),
|
||
(BYTE) pwItemInfo[1],
|
||
(BYTE) pwItemInfo[2],
|
||
pwItemInfo[3],
|
||
pwItemInfo[4]
|
||
);
|
||
|
||
wOptParam = pwItemInfo[5];
|
||
pOptParam = PFillOutOptType(pUiData->pOptType,
|
||
pwItemInfo[6],
|
||
wOptParam,
|
||
pUiData->ci.hHeap);
|
||
|
||
if (pOptParam == NULL)
|
||
return FALSE;
|
||
|
||
pwItemInfo += 7;
|
||
while (wOptParam--)
|
||
{
|
||
pOptParam->cbSize = sizeof(OPTPARAM);
|
||
pOptParam->pData = (PWSTR) *pwItemInfo++;
|
||
pOptParam->IconID = *pwItemInfo++;
|
||
pOptParam++;
|
||
}
|
||
|
||
ASSERT(*pwItemInfo == ITEM_INFO_SIGNATURE);
|
||
|
||
if (pFeature)
|
||
{
|
||
SETUSERDATA_KEYWORDNAME(pUiData->ci, pOptItem, pFeature);
|
||
|
||
#ifdef UNIDRV
|
||
|
||
if (pUiData->ci.pUIInfo->loHelpFileName &&
|
||
pFeature->iHelpIndex != UNUSED_ITEM )
|
||
{
|
||
//
|
||
// Allocate memory for OIEXT
|
||
//
|
||
|
||
POIEXT pOIExt = HEAPALLOC(pUiData->ci.hHeap, sizeof(OIEXT));
|
||
|
||
if (pOIExt)
|
||
{
|
||
pOIExt->cbSize = sizeof(OIEXT);
|
||
pOIExt->Flags = 0;
|
||
pOIExt->hInstCaller = NULL;
|
||
pOIExt->pHelpFile = OFFSET_TO_POINTER(pUiData->ci.pUIInfo->pubResourceData,
|
||
pUiData->ci.pUIInfo->loHelpFileName);
|
||
pOptItem->pOIExt = pOIExt;
|
||
pOptItem->HelpIndex = pFeature->iHelpIndex;
|
||
pOptItem->Flags |= OPTIF_HAS_POIEXT;
|
||
}
|
||
|
||
}
|
||
#endif // UNIDRV
|
||
}
|
||
pUiData->pOptItem++;
|
||
pUiData->pOptType++;
|
||
}
|
||
|
||
pUiData->dwOptItem++;
|
||
pUiData->dwOptType++;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
BPackUDArrowItemTemplate(
|
||
IN OUT PUIDATA pUiData,
|
||
IN CONST WORD pwItemInfo[],
|
||
IN DWORD dwSelection,
|
||
IN DWORD dwMaxVal,
|
||
IN PFEATURE pFeature
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Pack an updown arrow item using the specified template
|
||
|
||
Arguments:
|
||
|
||
pUiData, pwItemInfo, dwSelection - same as for BPackOptItemTemplate
|
||
dwMaxVal - maximum value for the updown arrow item
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE if there is an error
|
||
|
||
--*/
|
||
|
||
{
|
||
POPTTYPE pOptType = pUiData->pOptType;
|
||
|
||
if (! BPackOptItemTemplate(pUiData, pwItemInfo, dwSelection, pFeature))
|
||
return FALSE;
|
||
|
||
if (pOptType)
|
||
pOptType->pOptParam[1].lParam = dwMaxVal;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
POPTPARAM
|
||
PFillOutOptType(
|
||
OUT POPTTYPE pOptType,
|
||
IN DWORD dwType,
|
||
IN DWORD dwParams,
|
||
IN HANDLE hHeap
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Fill out an OPTTYPE structure
|
||
|
||
Arguments:
|
||
|
||
pOpttype - Pointer to OPTTYPE structure to be filled out
|
||
wType - Value for OPTTYPE.Type field
|
||
wParams - 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 = (WORD) dwParams;
|
||
pOptType->Type = (BYTE) dwType;
|
||
|
||
pOptParam = HEAPALLOC(hHeap, sizeof(OPTPARAM) * dwParams);
|
||
|
||
if (pOptParam != NULL)
|
||
pOptType->pOptParam = pOptParam;
|
||
else
|
||
ERR(("Memory allocation failed\n"));
|
||
|
||
return pOptParam;
|
||
}
|
||
|
||
|
||
BOOL
|
||
BShouldDisplayGenericFeature(
|
||
IN PFEATURE pFeature,
|
||
IN BOOL bPrinterSticky
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine whether a printer feature should be displayed
|
||
as a generic feature
|
||
|
||
Arguments:
|
||
|
||
pFeature - Points to a FEATURE structure
|
||
pPrinterSticky - Whether the feature is printer-sticky or doc-sticky
|
||
|
||
Return Value:
|
||
|
||
TRUE if the feature should be displayed as a generic feature
|
||
FALSE if it should not be
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Check if the feature is specified marked as non-displayable
|
||
// and make sure the feature type is appropriate
|
||
//
|
||
|
||
if ((pFeature->dwFlags & FEATURE_FLAG_NOUI) ||
|
||
(bPrinterSticky &&
|
||
pFeature->dwFeatureType != FEATURETYPE_PRINTERPROPERTY) ||
|
||
(!bPrinterSticky &&
|
||
pFeature->dwFeatureType != FEATURETYPE_DOCPROPERTY &&
|
||
pFeature->dwFeatureType != FEATURETYPE_JOBPROPERTY))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Exclude those features which are explicitly handled
|
||
// and also those which don't have any options
|
||
//
|
||
|
||
return (pFeature->Options.dwCount >= MIN_OPTIONS_ALLOWED) &&
|
||
(pFeature->dwFeatureID == GID_UNKNOWN ||
|
||
pFeature->dwFeatureID == GID_OUTPUTBIN ||
|
||
pFeature->dwFeatureID == GID_MEMOPTION);
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
DwCountDisplayableGenericFeature(
|
||
IN PUIDATA pUiData,
|
||
BOOL bPrinterSticky
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Count the number of features which can be displayed
|
||
as generic features
|
||
|
||
Arguments:
|
||
|
||
pUiData - Points to UIDATA structure
|
||
pPrinterSticky - Whether the feature is printer-sticky or doc-sticky
|
||
|
||
Return Value:
|
||
|
||
Number of features which can be displayed as generic features
|
||
|
||
--*/
|
||
|
||
{
|
||
PFEATURE pFeature;
|
||
DWORD dwFeature, dwCount = 0;
|
||
|
||
pFeature = PGetIndexedFeature(pUiData->ci.pUIInfo, 0);
|
||
dwFeature = pUiData->ci.pRawData->dwDocumentFeatures +
|
||
pUiData->ci.pRawData->dwPrinterFeatures;
|
||
|
||
if (pFeature && dwFeature)
|
||
{
|
||
for ( ; dwFeature--; pFeature++)
|
||
{
|
||
if (BShouldDisplayGenericFeature(pFeature, bPrinterSticky))
|
||
dwCount++;
|
||
}
|
||
}
|
||
|
||
return dwCount;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
DwGuessOptionIconID(
|
||
PUIINFO pUIInfo,
|
||
PFEATURE pFeature,
|
||
POPTION pOption
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Try to make an intelligent guess as to what icon
|
||
to use for a generic printer feature option
|
||
|
||
Arguments:
|
||
|
||
pUIInfo - Points to UIINFO structure
|
||
pFeature - Points to the feature in question
|
||
pOption - Points to the option in question
|
||
|
||
Return Value:
|
||
|
||
Icon resource ID appropriate for the feature option
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dwIconID, iRes;
|
||
|
||
switch (pFeature->dwFeatureID)
|
||
{
|
||
case GID_RESOLUTION:
|
||
|
||
iRes = max(((PRESOLUTION) pOption)->iXdpi, ((PRESOLUTION) pOption)->iYdpi);
|
||
|
||
if (iRes <= 150)
|
||
dwIconID = IDI_CPSUI_RES_DRAFT;
|
||
else if (iRes <= 300)
|
||
dwIconID = IDI_CPSUI_RES_LOW;
|
||
else if (iRes <= 600)
|
||
dwIconID = IDI_CPSUI_RES_MEDIUM;
|
||
else if (iRes <= 900)
|
||
dwIconID = IDI_CPSUI_RES_HIGH;
|
||
else
|
||
dwIconID = IDI_CPSUI_RES_PRESENTATION;
|
||
|
||
break;
|
||
|
||
case GID_DUPLEX:
|
||
|
||
switch (((PDUPLEX) pOption)->dwDuplexID)
|
||
{
|
||
case DMDUP_VERTICAL:
|
||
dwIconID = IDI_CPSUI_DUPLEX_VERT;
|
||
break;
|
||
|
||
case DMDUP_HORIZONTAL:
|
||
dwIconID = IDI_CPSUI_DUPLEX_HORZ;
|
||
break;
|
||
|
||
default:
|
||
dwIconID = IDI_CPSUI_DUPLEX_NONE;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case GID_ORIENTATION:
|
||
|
||
switch (((PORIENTATION) pOption)->dwRotationAngle)
|
||
{
|
||
case ROTATE_270:
|
||
dwIconID = IDI_CPSUI_LANDSCAPE;
|
||
break;
|
||
|
||
case ROTATE_90:
|
||
dwIconID = IDI_CPSUI_ROT_LAND;
|
||
break;
|
||
|
||
default:
|
||
dwIconID = IDI_CPSUI_PORTRAIT;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case GID_INPUTSLOT:
|
||
dwIconID = IDI_CPSUI_PAPER_TRAY;
|
||
break;
|
||
|
||
case GID_PAGEPROTECTION:
|
||
dwIconID = IDI_CPSUI_PAGE_PROTECT;
|
||
break;
|
||
|
||
default:
|
||
dwIconID = IDI_CPSUI_GENERIC_OPTION;
|
||
break;
|
||
}
|
||
|
||
return dwIconID;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
BPackItemPrinterFeature(
|
||
PUIDATA pUiData,
|
||
PFEATURE pFeature,
|
||
DWORD dwLevel,
|
||
DWORD dwPub,
|
||
ULONG_PTR dwUserData,
|
||
DWORD dwHelpIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Pack a single printer feature item
|
||
|
||
Arguments:
|
||
|
||
pUiData - Points to UIDATA structure
|
||
pFeature - Points to the printer feature to be packed
|
||
dwLevel - Treeview item level
|
||
dwPub - DMPUB_ identifier
|
||
dwUserData - User data to be associated with the item
|
||
dwHelpIndex - Help index to be associated with the item
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE if there is an error
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dwCount, dwIndex;
|
||
DWORD dwFeature, dwSel;
|
||
POPTION pOption;
|
||
POPTTYPE pOptTypeHack;
|
||
POPTPARAM pOptParam;
|
||
PCOMMONINFO pci;
|
||
|
||
if (pFeature == NULL ||
|
||
(pFeature->dwFlags & FEATURE_FLAG_NOUI) ||
|
||
(dwCount = pFeature->Options.dwCount) < MIN_OPTIONS_ALLOWED)
|
||
return TRUE;
|
||
|
||
//
|
||
// HACK: for Orientation and Duplex feature
|
||
// They must be of type TVOT_2STATES or TVOT_3STATES.
|
||
// If not, compstui will get confused.
|
||
//
|
||
|
||
if (dwPub == DMPUB_ORIENTATION || dwPub == DMPUB_DUPLEX)
|
||
{
|
||
if (dwCount != 2 && dwCount != 3)
|
||
{
|
||
WARNING(("Unexpected number of Orientation/Duplex options\n"));
|
||
return TRUE;
|
||
}
|
||
|
||
pOptTypeHack = pUiData->pOptType;
|
||
}
|
||
else
|
||
pOptTypeHack = NULL;
|
||
|
||
pUiData->dwOptItem++;
|
||
pUiData->dwOptType++;
|
||
|
||
if (pUiData->pOptItem == NULL)
|
||
return TRUE;
|
||
|
||
//
|
||
// Find out the current selection first
|
||
// DCR: needs to support PICKMANY
|
||
//
|
||
|
||
pci = (PCOMMONINFO) pUiData;
|
||
dwFeature = GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature);
|
||
dwSel = pci->pCombinedOptions[dwFeature].ubCurOptIndex;
|
||
|
||
if (dwSel >= dwCount)
|
||
dwSel = 0;
|
||
|
||
//
|
||
// If we are in this function, we must have already successfully
|
||
// called function PFillUiData(), where the pci->hHeap is created.
|
||
//
|
||
|
||
ASSERT(pci->hHeap != NULL);
|
||
|
||
//
|
||
// Fill in the OPTITEM structure
|
||
//
|
||
|
||
FILLOPTITEM(pUiData->pOptItem,
|
||
pUiData->pOptType,
|
||
PGetReadOnlyDisplayName(pci, pFeature->loDisplayName),
|
||
ULongToPtr(dwSel),
|
||
dwLevel,
|
||
dwPub,
|
||
dwUserData,
|
||
dwHelpIndex);
|
||
|
||
#ifdef UNIDRV
|
||
//
|
||
// Supports OEM help file. If helpfile and helpindex are defined,
|
||
// we will use the help id specified by the GPD. According to GPD spec,
|
||
// zero loHelpFileName means no help file name specified.
|
||
//
|
||
|
||
if (pci->pUIInfo->loHelpFileName &&
|
||
pFeature->iHelpIndex != UNUSED_ITEM )
|
||
{
|
||
//
|
||
// Allocate memory for OIEXT
|
||
//
|
||
|
||
POIEXT pOIExt = HEAPALLOC(pci->hHeap, sizeof(OIEXT));
|
||
|
||
if (pOIExt)
|
||
{
|
||
pOIExt->cbSize = sizeof(OIEXT);
|
||
pOIExt->Flags = 0;
|
||
pOIExt->hInstCaller = NULL;
|
||
pOIExt->pHelpFile = OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData,
|
||
pci->pUIInfo->loHelpFileName);
|
||
pUiData->pOptItem->pOIExt = pOIExt;
|
||
pUiData->pOptItem->HelpIndex = pFeature->iHelpIndex;
|
||
pUiData->pOptItem->Flags |= OPTIF_HAS_POIEXT;
|
||
}
|
||
|
||
}
|
||
#endif // UNIDRV
|
||
|
||
pOptParam = PFillOutOptType(pUiData->pOptType, TVOT_LISTBOX, dwCount, pci->hHeap);
|
||
|
||
if (pOptParam == NULL)
|
||
return FALSE;
|
||
|
||
if (pOptTypeHack)
|
||
pOptTypeHack->Type = (dwCount == 2) ? TVOT_2STATES : TVOT_3STATES;
|
||
|
||
//
|
||
// Get the list of options for this features
|
||
//
|
||
|
||
for (dwIndex=0; dwIndex < dwCount; dwIndex++, pOptParam++)
|
||
{
|
||
//
|
||
// Fill in the options name
|
||
//
|
||
|
||
pOption = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex);
|
||
ASSERT(pOption != NULL);
|
||
|
||
pOptParam->cbSize = sizeof(OPTPARAM);
|
||
pOptParam->pData = GET_OPTION_DISPLAY_NAME(pci, pOption);
|
||
|
||
//
|
||
// Try to figure out the appropriate icon to use
|
||
// If the icon comes from the resource DLL, we need to load
|
||
// it ourselves and give compstui an HICON. Otherwise,
|
||
// we try to figure out the appropriate icon resource ID.
|
||
//
|
||
|
||
if (pOption->loResourceIcon &&
|
||
(pOptParam->IconID = HLoadIconFromResourceDLL(pci, pOption->loResourceIcon)))
|
||
{
|
||
pOptParam->Flags |= OPTPF_ICONID_AS_HICON;
|
||
}
|
||
else
|
||
pOptParam->IconID = DwGuessOptionIconID(pci->pUIInfo, pFeature, pOption);
|
||
}
|
||
|
||
//
|
||
// Set the Keyword name for pOptItem->UserData
|
||
//
|
||
|
||
SETUSERDATA_KEYWORDNAME(pUiData->ci, pUiData->pOptItem, pFeature);
|
||
|
||
pUiData->pOptItem++;
|
||
pUiData->pOptType++;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
BPackItemGenericOptions(
|
||
IN OUT PUIDATA pUiData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Pack generic printer features items (doc-sticky or printer-sticky)
|
||
|
||
Arguments:
|
||
|
||
pUiData - Points to UIDATA structure
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE if there is an error.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Extended push button for restoring to default feature selections
|
||
//
|
||
|
||
static EXTPUSH ExtPush =
|
||
{
|
||
sizeof(EXTPUSH),
|
||
EPF_NO_DOT_DOT_DOT,
|
||
(PWSTR) IDS_RESTORE_DEFAULTS,
|
||
NULL,
|
||
0,
|
||
0,
|
||
};
|
||
|
||
POPTITEM pOptItem;
|
||
DWORD dwHelpIndex, dwIconId;
|
||
PFEATURE pFeatures;
|
||
DWORD dwFeatures;
|
||
BOOL bPrinterSticky;
|
||
|
||
//
|
||
// If there are no generic features to display, simply return success
|
||
//
|
||
|
||
bPrinterSticky = (pUiData->iMode == MODE_PRINTER_STICKY);
|
||
|
||
if (DwCountDisplayableGenericFeature(pUiData, bPrinterSticky) == 0)
|
||
return TRUE;
|
||
|
||
//
|
||
// Add the group header item
|
||
//
|
||
|
||
pOptItem = pUiData->pOptItem;
|
||
|
||
if (bPrinterSticky)
|
||
{
|
||
VPackOptItemGroupHeader(
|
||
pUiData,
|
||
IDS_INSTALLABLE_OPTIONS,
|
||
IDI_CPSUI_INSTALLABLE_OPTION,
|
||
HELP_INDEX_INSTALLABLE_OPTIONS);
|
||
}
|
||
else
|
||
{
|
||
VPackOptItemGroupHeader(
|
||
pUiData,
|
||
IDS_PRINTER_FEATURES,
|
||
IDI_CPSUI_PRINTER_FEATURE,
|
||
HELP_INDEX_PRINTER_FEATURES);
|
||
}
|
||
|
||
if (pOptItem != NULL && !bPrinterSticky)
|
||
{
|
||
//
|
||
// "Restore Defaults" button
|
||
//
|
||
|
||
pUiData->pFeatureHdrItem = pOptItem;
|
||
pOptItem->Flags |= (OPTIF_EXT_IS_EXTPUSH|OPTIF_CALLBACK);
|
||
pOptItem->pExtPush = &ExtPush;
|
||
}
|
||
|
||
pOptItem = pUiData->pOptItem;
|
||
|
||
//
|
||
// Figure out the correct help index and icon ID
|
||
// depending on whether we're dealing with printer-sticky
|
||
// features or document-sticky printer features
|
||
//
|
||
|
||
if (bPrinterSticky)
|
||
{
|
||
dwHelpIndex = HELP_INDEX_INSTALLABLE_OPTIONS;
|
||
dwIconId = IDI_CPSUI_INSTALLABLE_OPTION;
|
||
}
|
||
else
|
||
{
|
||
dwHelpIndex = HELP_INDEX_PRINTER_FEATURES;
|
||
dwIconId = IDI_CPSUI_PRINTER_FEATURE;
|
||
}
|
||
|
||
//
|
||
// Go through each printer feature
|
||
//
|
||
|
||
pFeatures = PGetIndexedFeature(pUiData->ci.pUIInfo, 0);
|
||
dwFeatures = pUiData->ci.pRawData->dwDocumentFeatures +
|
||
pUiData->ci.pRawData->dwPrinterFeatures;
|
||
|
||
ASSERT(pFeatures != NULL);
|
||
|
||
for ( ; dwFeatures--; pFeatures++)
|
||
{
|
||
//
|
||
// Don't do anything if it's the feature has no options OR
|
||
// If it's not a generic feature.
|
||
//
|
||
|
||
if (BShouldDisplayGenericFeature(pFeatures, bPrinterSticky) &&
|
||
!BPackItemPrinterFeature(pUiData,
|
||
pFeatures,
|
||
TVITEM_LEVEL2,
|
||
DMPUB_NONE,
|
||
(ULONG_PTR) pFeatures,
|
||
dwHelpIndex))
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
if (pOptItem != NULL)
|
||
{
|
||
pUiData->pFeatureItems = pOptItem;
|
||
pUiData->dwFeatureItem = (DWORD)(pUiData->pOptItem - pOptItem);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
PFEATURE
|
||
PGetFeatureFromItem(
|
||
IN PUIINFO pUIInfo,
|
||
IN OUT POPTITEM pOptItem,
|
||
OUT PDWORD pdwFeatureIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get the feature index for a given pOptItem
|
||
|
||
Arguments:
|
||
|
||
pUIInfo - pointer to UIINFO
|
||
pOptItem - pointer to item to look for feature id
|
||
pdwFeatureIndex - pointer to contain the value of returned index
|
||
|
||
Return Value:
|
||
|
||
Pointer to FEATURE structure associated with the item
|
||
NULL if no such feature exists.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFEATURE pFeature = NULL;
|
||
|
||
//
|
||
// Get the dwFeature, which is the index into pOptionsArray
|
||
//
|
||
|
||
if (ISPRINTERFEATUREITEM(pOptItem->UserData))
|
||
{
|
||
//
|
||
// Note: Generic Features contains pointer to feature (pFeature)
|
||
// in pOptItem->UserData
|
||
//
|
||
|
||
pFeature = (PFEATURE) GETUSERDATAITEM(pOptItem->UserData);
|
||
}
|
||
else
|
||
{
|
||
DWORD dwFeatureId;
|
||
|
||
switch (GETUSERDATAITEM(pOptItem->UserData))
|
||
{
|
||
case FORMNAME_ITEM:
|
||
dwFeatureId = GID_PAGESIZE;
|
||
break;
|
||
|
||
case DUPLEX_ITEM:
|
||
dwFeatureId = GID_DUPLEX;
|
||
break;
|
||
|
||
case RESOLUTION_ITEM:
|
||
dwFeatureId = GID_RESOLUTION;
|
||
break;
|
||
|
||
case MEDIATYPE_ITEM:
|
||
dwFeatureId = GID_MEDIATYPE;
|
||
break;
|
||
|
||
case INPUTSLOT_ITEM:
|
||
dwFeatureId = GID_INPUTSLOT;
|
||
break;
|
||
|
||
case FORM_TRAY_ITEM:
|
||
dwFeatureId = GID_INPUTSLOT;
|
||
break;
|
||
|
||
case COLORMODE_ITEM:
|
||
dwFeatureId = GID_COLORMODE;
|
||
break;
|
||
|
||
case ORIENTATION_ITEM:
|
||
dwFeatureId = GID_ORIENTATION;
|
||
break;
|
||
|
||
case PAGE_PROTECT_ITEM:
|
||
dwFeatureId = GID_PAGEPROTECTION;
|
||
break;
|
||
|
||
case COPIES_COLLATE_ITEM:
|
||
dwFeatureId = GID_COLLATE;
|
||
break;
|
||
|
||
case HALFTONING_ITEM:
|
||
dwFeatureId = GID_HALFTONING;
|
||
break;
|
||
|
||
default:
|
||
dwFeatureId = GID_UNKNOWN;
|
||
break;
|
||
}
|
||
|
||
if (dwFeatureId != GID_UNKNOWN)
|
||
pFeature = GET_PREDEFINED_FEATURE(pUIInfo, dwFeatureId);
|
||
}
|
||
|
||
if (pFeature && pdwFeatureIndex)
|
||
*pdwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature);
|
||
|
||
return pFeature;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
VUpdateOptionsArrayWithSelection(
|
||
IN OUT PUIDATA pUiData,
|
||
IN POPTITEM pOptItem
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Update the options array with the current selection
|
||
|
||
Arguments:
|
||
|
||
pUiData - Points to UIDATA structure
|
||
pOptItem - Specifies the item whose selection has changed
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
{
|
||
PFEATURE pFeature;
|
||
DWORD dwFeatureIndex;
|
||
|
||
//
|
||
// Get the feature associated with the current item
|
||
//
|
||
|
||
pFeature = PGetFeatureFromItem(pUiData->ci.pUIInfo, pOptItem, &dwFeatureIndex);
|
||
if (pFeature == NULL)
|
||
return;
|
||
|
||
if (pOptItem->Sel < 0 || pOptItem->Sel >= (LONG) pFeature->Options.dwCount)
|
||
{
|
||
RIP(("Invalid selection for the current item\n"));
|
||
return;
|
||
}
|
||
|
||
ZeroMemory(pUiData->abEnabledOptions, sizeof(pUiData->abEnabledOptions));
|
||
pUiData->abEnabledOptions[pOptItem->Sel] = TRUE;
|
||
|
||
ReconstructOptionArray(pUiData->ci.pRawData,
|
||
pUiData->ci.pCombinedOptions,
|
||
MAX_COMBINED_OPTIONS,
|
||
dwFeatureIndex,
|
||
pUiData->abEnabledOptions);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
VMarkSelectionConstrained(
|
||
IN OUT POPTITEM pOptItem,
|
||
IN DWORD dwIndex,
|
||
IN BOOL bEnable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Indicate whether a selection is constrained or not
|
||
|
||
Arguments:
|
||
|
||
pOptItem - Pointer to the OPTITEM in question
|
||
pOptParam - Specifies the index of the OPTPARAM in question
|
||
bEnable - Whether the selection is constrained or not
|
||
Enable means not constrained!
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
Note:
|
||
|
||
bEnable is the returned value from EnumEnabledOptions,
|
||
|
||
bEnable is FALSE if the option is contrained by some
|
||
other feature, selections.
|
||
|
||
bEnable is TRUE if the options is not constrained
|
||
by other feature, selections.
|
||
|
||
--*/
|
||
|
||
{
|
||
POPTPARAM pOptParam;
|
||
|
||
//
|
||
// This function only work on certain types of OPTTYPE
|
||
//
|
||
|
||
ASSERT(pOptItem->pOptType->Type == TVOT_2STATES ||
|
||
pOptItem->pOptType->Type == TVOT_3STATES ||
|
||
pOptItem->pOptType->Type == TVOT_LISTBOX ||
|
||
pOptItem->pOptType->Type == TVOT_COMBOBOX);
|
||
|
||
pOptParam = pOptItem->pOptType->pOptParam + dwIndex;
|
||
|
||
//
|
||
// Set the constrained flag or clear it depending on the latest
|
||
// check with EnumEnabledOptions
|
||
//
|
||
|
||
if (!bEnable && ! (pOptParam->Flags & CONSTRAINED_FLAG))
|
||
{
|
||
pOptParam->Flags |= CONSTRAINED_FLAG;
|
||
pOptItem->Flags |= OPTIF_CHANGED;
|
||
}
|
||
else if (bEnable && (pOptParam->Flags & CONSTRAINED_FLAG))
|
||
{
|
||
pOptParam->Flags &= ~CONSTRAINED_FLAG;
|
||
pOptItem->Flags |= OPTIF_CHANGED;
|
||
}
|
||
|
||
pOptParam->lParam = (LONG) bEnable;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
VPropShowConstraints(
|
||
IN PUIDATA pUiData,
|
||
IN INT iMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Indicate which items are constrained.
|
||
General rule - Any features that has a coresponding an applicable GID or a
|
||
Generic Feature Item, check for constrained. Ignore all others
|
||
because it's not applicable.
|
||
|
||
Arguments:
|
||
|
||
pUiData - Pointer to our UIDATA structure
|
||
iMode - MODE_DOCANDPRINTER_STICKY, MODE_PRINTER_STICKY
|
||
Return Value:
|
||
|
||
NONE
|
||
--*/
|
||
|
||
{
|
||
POPTITEM pOptItem;
|
||
DWORD dwOptItem;
|
||
DWORD dwFeature, dwOption, dwNumOptions, dwIndex;
|
||
|
||
#ifdef PSCRIPT
|
||
|
||
if (iMode != MODE_PRINTER_STICKY)
|
||
{
|
||
VSyncRevPrintAndOutputOrder(pUiData, NULL);
|
||
}
|
||
|
||
#endif // PSCRIPT
|
||
|
||
//
|
||
// Go through all the features in the treeview
|
||
//
|
||
|
||
pOptItem = pUiData->pDrvOptItem;
|
||
dwOptItem = pUiData->dwDrvOptItem;
|
||
|
||
for ( ; dwOptItem--; pOptItem++)
|
||
{
|
||
|
||
if (! ISCONSTRAINABLEITEM(pOptItem->UserData) ||
|
||
! PGetFeatureFromItem(pUiData->ci.pUIInfo, pOptItem, &dwFeature))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Call the parser to get which options to be disable, or contrained
|
||
// for this feature , so need to gray it out.
|
||
//
|
||
|
||
ZeroMemory(pUiData->abEnabledOptions, sizeof(pUiData->abEnabledOptions));
|
||
|
||
if (! EnumEnabledOptions(pUiData->ci.pRawData,
|
||
pUiData->ci.pCombinedOptions,
|
||
dwFeature,
|
||
pUiData->abEnabledOptions,
|
||
iMode))
|
||
{
|
||
VERBOSE(("EnumEnabledOptions failed\n"));
|
||
}
|
||
|
||
//
|
||
// Loop through all options and mark the constraint
|
||
//
|
||
|
||
dwNumOptions = pOptItem->pOptType->Count;
|
||
|
||
if (GETUSERDATAITEM(pOptItem->UserData) == FORMNAME_ITEM)
|
||
{
|
||
for (dwIndex = 0; dwIndex < dwNumOptions; dwIndex++)
|
||
{
|
||
dwOption = pUiData->pwPaperFeatures[dwIndex];
|
||
|
||
if (dwOption == OPTION_INDEX_ANY)
|
||
continue;
|
||
|
||
VMarkSelectionConstrained(pOptItem,
|
||
dwIndex,
|
||
pUiData->abEnabledOptions[dwOption]);
|
||
}
|
||
}
|
||
else if (GETUSERDATAITEM(pOptItem->UserData) == FORM_TRAY_ITEM)
|
||
{
|
||
if (pOptItem == pUiData->pFormTrayItems)
|
||
{
|
||
POPTITEM pTrayItem;
|
||
PBOOL pbEnable;
|
||
|
||
//
|
||
// Update form-to-tray assignment table items
|
||
//
|
||
|
||
pbEnable = pUiData->abEnabledOptions;
|
||
pTrayItem = pUiData->pFormTrayItems;
|
||
dwIndex = pUiData->dwFormTrayItem;
|
||
|
||
for ( ; dwIndex--; pTrayItem++, pbEnable++)
|
||
{
|
||
if (pTrayItem->Flags & OPTIF_HIDE)
|
||
continue;
|
||
|
||
if (*pbEnable && (pTrayItem->Flags & OPTIF_DISABLED))
|
||
{
|
||
pTrayItem->Flags &= ~OPTIF_DISABLED;
|
||
pTrayItem->Flags |= OPTIF_CHANGED;
|
||
}
|
||
else if (!*pbEnable && !(pTrayItem->Flags & OPTIF_DISABLED))
|
||
{
|
||
pTrayItem->Flags |= (OPTIF_DISABLED|OPTIF_CHANGED);
|
||
pTrayItem->Sel = -1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (dwOption=0; dwOption < dwNumOptions; dwOption++)
|
||
{
|
||
VMarkSelectionConstrained(pOptItem,
|
||
dwOption,
|
||
pUiData->abEnabledOptions[dwOption]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
INT_PTR CALLBACK
|
||
BConflictsDlgProc(
|
||
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
|
||
|
||
--*/
|
||
|
||
{
|
||
PDLGPARAM pDlgParam;
|
||
POPTITEM pOptItem;
|
||
PFEATURE pFeature;
|
||
POPTION pOption;
|
||
DWORD dwFeature, dwOption;
|
||
PCWSTR pDisplayName;
|
||
WCHAR awchBuf[MAX_DISPLAY_NAME];
|
||
PCOMMONINFO pci;
|
||
CONFLICTPAIR ConflictPair;
|
||
|
||
|
||
switch (uMsg)
|
||
{
|
||
case WM_INITDIALOG:
|
||
|
||
pDlgParam = (PDLGPARAM) lParam;
|
||
ASSERT(pDlgParam != NULL);
|
||
|
||
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pDlgParam);
|
||
|
||
pci = (PCOMMONINFO) pDlgParam->pUiData;
|
||
pOptItem = pDlgParam->pOptItem;
|
||
|
||
if (GETUSERDATAITEM(pOptItem->UserData) == FORMNAME_ITEM)
|
||
dwOption = pDlgParam->pUiData->pwPaperFeatures[pOptItem->Sel];
|
||
else
|
||
dwOption = pOptItem->Sel;
|
||
|
||
//
|
||
// Get the feature id for the current feature and selection
|
||
//
|
||
|
||
if (! PGetFeatureFromItem(pci->pUIInfo, pOptItem, &dwFeature))
|
||
return FALSE;
|
||
|
||
//
|
||
// Get the first conflicting feature, option for the current pair
|
||
//
|
||
|
||
if (! EnumNewPickOneUIConflict(pci->pRawData,
|
||
pci->pCombinedOptions,
|
||
dwFeature,
|
||
dwOption,
|
||
&ConflictPair))
|
||
{
|
||
ERR(("No conflict found?\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
pFeature = PGetIndexedFeature(pci->pUIInfo, ConflictPair.dwFeatureIndex1);
|
||
pOption = PGetIndexedOption(pci->pUIInfo, pFeature, ConflictPair.dwOptionIndex1);
|
||
|
||
//
|
||
// Display the current feature selection
|
||
// Get feature name first
|
||
//
|
||
|
||
if (pDisplayName = PGetReadOnlyDisplayName(pci, pFeature->loDisplayName))
|
||
{
|
||
wcscpy(awchBuf, pDisplayName);
|
||
wcscat(awchBuf, TEXT(" : "));
|
||
}
|
||
|
||
//
|
||
// Kludgy fix for form - We show the form enumerated by
|
||
// form database and map these logical forms to our supported physical
|
||
// papersize. So we have to notify the user with the logical form
|
||
// selected and not the mapped physical form returned by EnumConflict
|
||
//
|
||
|
||
if (pFeature->dwFeatureID == GID_PAGESIZE)
|
||
pDisplayName = pci->pdm->dmFormName;
|
||
else if (pOption)
|
||
pDisplayName = GET_OPTION_DISPLAY_NAME(pci, pOption);
|
||
else
|
||
pDisplayName = NULL;
|
||
|
||
if (pDisplayName)
|
||
wcscat(awchBuf, pDisplayName);
|
||
|
||
SetDlgItemText(hDlg, IDC_FEATURE1, awchBuf);
|
||
|
||
pFeature = PGetIndexedFeature(pci->pUIInfo, ConflictPair.dwFeatureIndex2);
|
||
pOption = PGetIndexedOption(pci->pUIInfo, pFeature, ConflictPair.dwOptionIndex2);
|
||
|
||
//
|
||
// Display the current feature selection
|
||
// Get feature name first
|
||
//
|
||
|
||
if (pDisplayName = PGetReadOnlyDisplayName(pci, pFeature->loDisplayName))
|
||
{
|
||
wcscpy(awchBuf, pDisplayName);
|
||
wcscat(awchBuf, TEXT(" : "));
|
||
}
|
||
|
||
|
||
if (pFeature->dwFeatureID == GID_PAGESIZE)
|
||
pDisplayName = pci->pdm->dmFormName;
|
||
else if (pOption)
|
||
pDisplayName = GET_OPTION_DISPLAY_NAME(pci, pOption);
|
||
else
|
||
pDisplayName = NULL;
|
||
|
||
if (pDisplayName)
|
||
wcscat(awchBuf, pDisplayName);
|
||
|
||
SetDlgItemText(hDlg, IDC_FEATURE2, awchBuf);
|
||
|
||
|
||
if (pDlgParam->bFinal)
|
||
{
|
||
//
|
||
// If user is trying to exit the dialog
|
||
//
|
||
|
||
ShowWindow(GetDlgItem(hDlg, IDC_IGNORE), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hDlg, IDC_CANCEL), SW_HIDE);
|
||
CheckRadioButton(hDlg, IDC_RESOLVE, IDC_CANCEL_FINAL, IDC_RESOLVE);
|
||
pDlgParam->dwResult = CONFLICT_RESOLVE;
|
||
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Hide the Resolve button
|
||
//
|
||
|
||
ShowWindow(GetDlgItem(hDlg, IDC_RESOLVE), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hDlg, IDC_CANCEL_FINAL), SW_HIDE);
|
||
CheckRadioButton(hDlg, IDC_IGNORE, IDC_CANCEL, IDC_IGNORE);
|
||
pDlgParam->dwResult = CONFLICT_IGNORE;
|
||
|
||
}
|
||
|
||
ShowWindow(hDlg, SW_SHOW);
|
||
return TRUE;
|
||
|
||
case WM_COMMAND:
|
||
|
||
pDlgParam = (PDLGPARAM)GetWindowLongPtr(hDlg, DWLP_USER);
|
||
|
||
switch (LOWORD(wParam))
|
||
{
|
||
case IDC_CANCEL:
|
||
case IDC_CANCEL_FINAL:
|
||
pDlgParam->dwResult = CONFLICT_CANCEL;
|
||
break;
|
||
|
||
case IDC_IGNORE:
|
||
pDlgParam->dwResult = CONFLICT_IGNORE;
|
||
break;
|
||
|
||
case IDC_RESOLVE:
|
||
pDlgParam->dwResult = CONFLICT_RESOLVE;
|
||
break;
|
||
|
||
case IDOK:
|
||
case IDCANCEL:
|
||
EndDialog(hDlg, LOWORD(wParam));
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
VUpdateOptItemList(
|
||
IN OUT PUIDATA pUiData,
|
||
IN POPTSELECT pOldCombinedOptions,
|
||
IN POPTSELECT pNewCombinedOptions
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Ssync up OPTITEM list with the updated options array.
|
||
|
||
Arguments:
|
||
|
||
pUiData - Pointer to our UIDATA structure
|
||
pOldCombinedOptions - A copy of the pre-resolved options array,
|
||
this should cut down the updating costs, only updated if it's changed
|
||
pNewCombinedOptions - the current options array
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD i, dwFeatures, dwDrvOptItem;
|
||
PFEATURE pFeature;
|
||
PUIINFO pUIInfo = pUiData->ci.pUIInfo;
|
||
PCSTR pKeywordName, pFeatureKeywordName;
|
||
POPTITEM pOptItem;
|
||
|
||
if (pUiData->dwDrvOptItem == 0)
|
||
{
|
||
//
|
||
// nothing to update
|
||
//
|
||
|
||
return;
|
||
}
|
||
|
||
dwFeatures = pUiData->ci.pRawData->dwDocumentFeatures +
|
||
pUiData->ci.pRawData->dwPrinterFeatures;
|
||
|
||
for (i = 0; i < dwFeatures; i++)
|
||
{
|
||
if (pOldCombinedOptions[i].ubCurOptIndex != pNewCombinedOptions[i].ubCurOptIndex)
|
||
{
|
||
dwDrvOptItem = pUiData->dwDrvOptItem;
|
||
pOptItem = pUiData->pDrvOptItem;
|
||
|
||
pFeature = PGetIndexedFeature(pUIInfo, i);
|
||
|
||
ASSERT(pFeature);
|
||
|
||
while( dwDrvOptItem--)
|
||
{
|
||
pKeywordName = GETUSERDATAKEYWORDNAME(pOptItem->UserData);
|
||
pFeatureKeywordName = OFFSET_TO_POINTER(pUIInfo->pubResourceData,
|
||
pFeature->loKeywordName);
|
||
|
||
ASSERT(pFeatureKeywordName);
|
||
|
||
if (pKeywordName && pFeatureKeywordName &&
|
||
(strcmp(pFeatureKeywordName, pKeywordName) == EQUAL_STRING))
|
||
break;
|
||
|
||
pOptItem++;
|
||
}
|
||
|
||
pOptItem->Sel = pNewCombinedOptions[i].ubCurOptIndex;
|
||
pOptItem->Flags |= OPTIF_CHANGED;
|
||
|
||
|
||
//
|
||
// This is necessary to ssync up the colormode changes with the color information
|
||
//
|
||
|
||
#ifdef UNIDRV
|
||
if (GETUSERDATAITEM(pOptItem->UserData) == COLORMODE_ITEM)
|
||
VSyncColorInformation(pUiData, pOptItem);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
VPropShowConstraints(pUiData,
|
||
(pUiData->iMode == MODE_PRINTER_STICKY) ? pUiData->iMode : MODE_DOCANDPRINTER_STICKY);
|
||
}
|
||
|
||
|
||
INT
|
||
ICheckConstraintsDlg(
|
||
IN OUT PUIDATA pUiData,
|
||
IN OUT POPTITEM pOptItem,
|
||
IN DWORD dwOptItem,
|
||
IN 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
|
||
dwOptItem - 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;
|
||
OPTSELECT OldCombinedOptions[MAX_COMBINED_OPTIONS];
|
||
|
||
|
||
DlgParam.pfnComPropSheet = pUiData->pfnComPropSheet;
|
||
DlgParam.hComPropSheet = pUiData->hComPropSheet;
|
||
DlgParam.pUiData = pUiData;
|
||
DlgParam.bFinal = bFinal;
|
||
DlgParam.dwResult = CONFLICT_NONE;
|
||
|
||
for ( ; dwOptItem--; pOptItem++)
|
||
{
|
||
//
|
||
// If the item is not constrainable, skip it.
|
||
//
|
||
|
||
if (! ISCONSTRAINABLEITEM(pOptItem->UserData))
|
||
continue;
|
||
|
||
//
|
||
// 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
|
||
//
|
||
|
||
if (IS_CONSTRAINED(pOptItem, pOptItem->Sel))
|
||
{
|
||
DlgParam.pOptItem = pOptItem;
|
||
DlgParam.dwResult = CONFLICT_NONE;
|
||
|
||
DialogBoxParam(ghInstance,
|
||
MAKEINTRESOURCE(IDD_CONFLICTS),
|
||
pUiData->hDlg,
|
||
(DLGPROC) BConflictsDlgProc,
|
||
(LPARAM) &DlgParam);
|
||
|
||
//
|
||
// Automatically resolve conflicts. We're being very
|
||
// simple-minded here, i.e. picking the first selection
|
||
// that's not constrained.
|
||
//
|
||
|
||
if (DlgParam.dwResult == CONFLICT_RESOLVE)
|
||
{
|
||
|
||
ASSERT((bFinal == TRUE));
|
||
|
||
//
|
||
// Save a copy the pre-resolve optionarray
|
||
//
|
||
|
||
CopyMemory(OldCombinedOptions,
|
||
pUiData->ci.pCombinedOptions,
|
||
MAX_COMBINED_OPTIONS * sizeof(OPTSELECT));
|
||
|
||
//
|
||
// Call the parsers to resolve the conflicts
|
||
//
|
||
// Note: If we're inside DrvDocumentPropertySheets,
|
||
// we'll call the parser to resolve conflicts between
|
||
// all printer features. Since all printer-sticky
|
||
// features have higher priority than all doc-sticky
|
||
// features, only doc-sticky option selections should
|
||
// be affected.
|
||
//
|
||
|
||
ResolveUIConflicts(pUiData->ci.pRawData,
|
||
pUiData->ci.pCombinedOptions,
|
||
MAX_COMBINED_OPTIONS,
|
||
(pUiData->iMode == MODE_PRINTER_STICKY) ?
|
||
pUiData->iMode :
|
||
MODE_DOCANDPRINTER_STICKY);
|
||
|
||
//
|
||
// Update the OPTITEM list to match the updated options array
|
||
//
|
||
|
||
VUpdateOptItemList(pUiData, OldCombinedOptions, pUiData->ci.pCombinedOptions);
|
||
|
||
}
|
||
else if (DlgParam.dwResult == CONFLICT_IGNORE)
|
||
{
|
||
//
|
||
// Ignore any future conflicts until the
|
||
// user tries to close the property sheet.
|
||
//
|
||
|
||
pUiData->bIgnoreConflict = TRUE;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
return DlgParam.dwResult;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
BOptItemSelectionsChanged(
|
||
IN POPTITEM pItems,
|
||
IN DWORD dwItems
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check if any of the OPTITEM's was changed by the user
|
||
|
||
Arguments:
|
||
|
||
pItems - Pointer to an array of OPTITEM's
|
||
dwItems - Number of OPTITEM's
|
||
|
||
Return Value:
|
||
|
||
TRUE if anything was changed, FALSE otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
for ( ; dwItems--; pItems++)
|
||
{
|
||
if (pItems->Flags & OPTIF_CHANGEONCE)
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
POPTITEM
|
||
PFindOptItem(
|
||
IN PUIDATA pUiData,
|
||
IN DWORD dwItemId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find an OPTITEM with the specified identifier
|
||
|
||
Arguments:
|
||
|
||
pUiData - Points to UIDATA structure
|
||
dwItemId - Specifies the interested item identifier
|
||
|
||
Return Value:
|
||
|
||
Pointer to OPTITEM with the specified id,
|
||
NULL if no such item is found
|
||
|
||
--*/
|
||
|
||
{
|
||
POPTITEM pOptItem = pUiData->pDrvOptItem;
|
||
DWORD dwOptItem = pUiData->dwDrvOptItem;
|
||
|
||
for ( ; dwOptItem--; pOptItem++)
|
||
{
|
||
if (GETUSERDATAITEM(pOptItem->UserData) == dwItemId)
|
||
return pOptItem;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
IDisplayErrorMessageBox(
|
||
HWND hwndParent,
|
||
UINT uType,
|
||
INT iTitleStrId,
|
||
INT iFormatStrId,
|
||
...
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Display an error message box
|
||
|
||
Arguments:
|
||
|
||
hwndParent - Handle to the parent window
|
||
uType - Type of message box to display
|
||
if 0, the default value is MB_OK | MB_ICONERROR
|
||
iTitleStrId - String resource ID for the message box title
|
||
iFormatStrId - String resource ID for the message itself.
|
||
This string can contain printf format specifications.
|
||
... - Optional arguments.
|
||
|
||
Return Value:
|
||
|
||
Return value from MessageBox() call.
|
||
|
||
--*/
|
||
|
||
#define MAX_MBTITLE_LEN 128
|
||
#define MAX_MBFORMAT_LEN 512
|
||
#define MAX_MBMESSAGE_LEN 1024
|
||
|
||
{
|
||
PWSTR pwstrTitle, pwstrFormat, pwstrMessage;
|
||
INT iResult;
|
||
va_list ap;
|
||
|
||
pwstrTitle = pwstrFormat = pwstrMessage = NULL;
|
||
|
||
if ((pwstrTitle = MemAllocZ(sizeof(WCHAR) * MAX_MBTITLE_LEN)) &&
|
||
(pwstrFormat = MemAllocZ(sizeof(WCHAR) * MAX_MBFORMAT_LEN)) &&
|
||
(pwstrMessage = MemAllocZ(sizeof(WCHAR) * MAX_MBMESSAGE_LEN)))
|
||
{
|
||
//
|
||
// Load message box title and format string resources
|
||
//
|
||
|
||
LoadString(ghInstance, iTitleStrId, pwstrTitle, MAX_MBTITLE_LEN);
|
||
LoadString(ghInstance, iFormatStrId, pwstrFormat, MAX_MBFORMAT_LEN);
|
||
|
||
//
|
||
// Compose the message string
|
||
//
|
||
|
||
va_start(ap, iFormatStrId);
|
||
wvsprintf(pwstrMessage, pwstrFormat, ap);
|
||
va_end(ap);
|
||
|
||
//
|
||
// Display the message box
|
||
//
|
||
|
||
if (uType == 0)
|
||
uType = MB_OK | MB_ICONERROR;
|
||
|
||
iResult = MessageBox(hwndParent, pwstrMessage, pwstrTitle, uType);
|
||
}
|
||
else
|
||
{
|
||
MessageBeep(MB_ICONERROR);
|
||
iResult = 0;
|
||
}
|
||
|
||
MemFree(pwstrTitle);
|
||
MemFree(pwstrFormat);
|
||
MemFree(pwstrMessage);
|
||
return iResult;
|
||
}
|
||
|