|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
forms.c
Abstract:
Functions for dealing with paper and forms.
[Environment:]
Win32 subsystem, PostScript driver
Revision History:
02/10/97 -davidx- Consistent handling of common printer info.
07/24/96 -amandan- Modified for common binary data and common UI module
07/25/95 -davidx- Created it.
--*/
#include "precomp.h"
BOOL BFormSupportedOnPrinter( IN PCOMMONINFO pci, IN PFORM_INFO_1 pForm, OUT PDWORD pdwOptionIndex )
/*++
Routine Description:
Determine whether a form is supported on a printer
Arguments: pci - Points to basic printer information pForm - Pointer to information about the form in question pdwOptionIndex - Returns the paper size option index corresponding to the specified form if the form is supported.
Return Value:
TRUE if the requested form is supported on the printer. FALSE otherwise.
--*/
{ PRAWBINARYDATA pRawData; PUIINFO pUIInfo; PFEATURE pFeature; DWORD dwIndex; CHAR chBuf[CCHPAPERNAME]; WCHAR wchBuf[CCHPAPERNAME];
//
// For a user-defined form, we only care about paper dimension.
// Let the parser handle this case.
//
if (! (pForm->Flags & (FORM_BUILTIN|FORM_PRINTER))) { *pdwOptionIndex = MapToDeviceOptIndex( pci->pInfoHeader, GID_PAGESIZE, pForm->Size.cx, pForm->Size.cy, NULL);
return (*pdwOptionIndex != OPTION_INDEX_ANY); }
//
// For predefined or driver-defined form, we need exact name and size match
//
chBuf[0] = NUL; *pdwOptionIndex = OPTION_INDEX_ANY;
if (! (pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE))) return FALSE;
for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++) { PPAGESIZE pPageSize; PWSTR pwstr; PSTR pstr; BOOL bNameMatch; LONG x, y;
pPageSize = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex); ASSERT(pPageSize != NULL);
//
// check if the size matches
//
x = MASTER_UNIT_TO_MICRON(pPageSize->szPaperSize.cx, pci->pUIInfo->ptMasterUnits.x);
y = MASTER_UNIT_TO_MICRON(pPageSize->szPaperSize.cy, pci->pUIInfo->ptMasterUnits.y);
if (abs(x - pForm->Size.cx) > 1000 || abs(y - pForm->Size.cy) > 1000) { continue; }
//
// check if the name matches
//
LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, wchBuf, CCHPAPERNAME); bNameMatch = (_tcsicmp(wchBuf, pForm->pName) == EQUAL_STRING);
if (!bNameMatch && (pForm->Flags & FORM_BUILTIN)) { PSTR pstrKeyword;
//
// special klugy for predefined form:
// if display name doesn't match, try to match the keyword string
//
if (chBuf[0] == NUL) { WideCharToMultiByte(1252, 0, pForm->pName, -1, chBuf, CCHPAPERNAME, NULL, NULL); chBuf[CCHPAPERNAME-1] = NUL; } pstrKeyword = OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData, pPageSize->GenericOption.loKeywordName);
ASSERT(pstrKeyword != NULL);
bNameMatch = (_stricmp(chBuf, pstrKeyword) == EQUAL_STRING); }
if (bNameMatch) { *pdwOptionIndex = dwIndex; return TRUE; } }
return FALSE; }
DWORD DwGuessFormIconID( PWSTR pFormName )
/*++
Routine Description:
Figure out the icon ID corresponding to the named form
Arguments:
pFormName - Pointer to the form name string
Return Value:
Icon ID corresponding to the specified form name
Note:
This is very klugy but I guess it's better than using the same icon for all forms. We try to differentiate envelopes from normal forms. We assume a form name refers an envelope if it contains word Envelope or Env.
--*/
#define MAXENVLEN 32
{ static WCHAR wchPrefix[MAXENVLEN], wchEnvelope[MAXENVLEN]; static INT iPrefixLen = 0, iEnvelopeLen = 0;
if (iPrefixLen <= 0 || iEnvelopeLen <= 0) { iPrefixLen = LoadString(ghInstance, IDS_ENV_PREFIX, wchPrefix, MAXENVLEN); iEnvelopeLen = LoadString(ghInstance, IDS_ENVELOPE, wchEnvelope, MAXENVLEN); }
if (iPrefixLen <= 0 || iEnvelopeLen <= 0) return IDI_CPSUI_STD_FORM;
while (*pFormName) { //
// Do we have a word matching our description?
//
if (_wcsnicmp(pFormName, wchPrefix, iPrefixLen) == EQUAL_STRING && (pFormName[iPrefixLen] == L' ' || pFormName[iPrefixLen] == NUL || _wcsnicmp(pFormName, wchEnvelope, iEnvelopeLen) == EQUAL_STRING)) { return IDI_CPSUI_ENVELOPE; }
//
// Move on to the next word
//
while (*pFormName && *pFormName != L' ') pFormName++;
while (*pFormName && *pFormName == L' ') pFormName++; }
return IDI_CPSUI_STD_FORM; }
ULONG_PTR HLoadFormIconResource( PUIDATA pUiData, DWORD dwIndex )
/*++
Routine Description:
Load the icon resource corresponding to the specified form
Arguments:
pUiData - Points to UIDATA structure dwIndex - Specifies the form index. It's used to index into pUiData->pwPaperFeatures to get the page size option index.
Return Value:
Icon resource handle corresponding to the specified form (casted as DWORD) 0 if the specified icon resource cannot be loaded
--*/
{ PFEATURE pFeature; POPTION pOption;
dwIndex = pUiData->pwPaperFeatures[dwIndex];
if ((pFeature = GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_PAGESIZE)) && (pOption = PGetIndexedOption(pUiData->ci.pUIInfo, pFeature, dwIndex)) && (pOption->loResourceIcon != 0)) { return HLoadIconFromResourceDLL(&pUiData->ci, pOption->loResourceIcon); }
return 0; }
POPTTYPE BFillFormNameOptType( IN PUIDATA pUiData )
/*++
Routine Description:
Initialize an OPTTYPE structure to hold information about the list of forms supported by a printer
Arguments:
pUiData - Pointer to UIDATA structure
Return Value:
Pointer to an OPTTYPE structure, NULL if there is an error
--*/
{ POPTTYPE pOptType; POPTPARAM pOptParam; DWORD dwFormName, dwIndex; PWSTR pFormName; PUIINFO pUIInfo = pUiData->ci.pUIInfo;
dwFormName = pUiData->dwFormNames;
//
// Allocate memory to hold OPTTYPE and OPTPARAM structures
//
pOptType = HEAPALLOC(pUiData->ci.hHeap, sizeof(OPTTYPE)); pOptParam = HEAPALLOC(pUiData->ci.hHeap, sizeof(OPTPARAM) * dwFormName);
if (!pOptType || !pOptParam) { ERR(("Memory allocation failed\n")); return NULL; }
//
// Initialize OPTTYPE structure
//
pOptType->cbSize = sizeof(OPTTYPE); pOptType->Count = (WORD) dwFormName; pOptType->Type = TVOT_LISTBOX; pOptType->pOptParam = pOptParam; pOptType->Style = OTS_LBCB_SORT | OTS_LBCB_INCL_ITEM_NONE;
//
// Enumerate the list of supported form names
//
pFormName = pUiData->pFormNames;
for (dwIndex=0; dwIndex < dwFormName; dwIndex++, pOptParam++) { pOptParam->cbSize = sizeof(OPTPARAM); pOptParam->pData = pFormName;
if (pOptParam->IconID = HLoadFormIconResource(pUiData, dwIndex)) pOptParam->Flags |= OPTPF_ICONID_AS_HICON; else pOptParam->IconID = DwGuessFormIconID(pFormName);
pFormName += CCHPAPERNAME; }
return pOptType; }
POPTTYPE PAdjustFormNameOptType( IN PUIDATA pUiData, IN POPTTYPE pOptType, IN DWORD dwTraySelection )
/*++
Routine Description:
Adjust the list of forms for each tray Check each form for support on printer tray
Given a tray selected, go through all the forms selection and determines which one conflicts with the current tray selection
Arguments:
pUiData - Pointer to our UIDATA structure pOptType - Pointer to OPTTYPE dwTraySelection - Tray index
Return Value:
TRUE if successful, FALSE otherwise
--*/
{ POPTPARAM pOptParam; DWORD dwOptParam, dwFormIndex; DWORD dwTrayFeatureIndex, dwFormFeatureIndex; PFEATURE pTrayFeature, pFormFeature; PUIINFO pUIInfo = pUiData->ci.pUIInfo;
dwOptParam = pOptType->Count;
//
// Find the pointers to InputSlot and PageSize features
//
pTrayFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_INPUTSLOT); pFormFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_PAGESIZE);
if (!pTrayFeature || !pFormFeature) return pOptType;
dwTrayFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pTrayFeature); dwFormFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFormFeature);
//
// Make a copy of the array of formname OPTPARAMs
//
if (dwTraySelection != 0) { POPTTYPE pNewType;
pNewType = HEAPALLOC(pUiData->ci.hHeap, sizeof(OPTTYPE)); pOptParam = HEAPALLOC(pUiData->ci.hHeap, sizeof(OPTPARAM) * dwOptParam);
if (!pNewType || !pOptParam) { ERR(("Memory allocation failed\n")); return NULL; }
CopyMemory(pNewType, pOptType, sizeof(OPTTYPE)); CopyMemory(pOptParam, pOptType->pOptParam, sizeof(OPTPARAM) * dwOptParam);
pNewType->pOptParam = pOptParam; pOptType = pNewType; } else pOptParam = pOptType->pOptParam;
//
// Go through each formname
// Check whether the current form tray feature, index
// conflicts with another form tray feature,index
//
for (dwFormIndex=0; dwFormIndex < dwOptParam; dwFormIndex++) { DWORD dwFormSelection = pUiData->pwPaperFeatures[dwFormIndex];
#ifdef PSCRIPT
//
// Hide only the option "PostScript Custom Page Size" itself. For other
// forms that are supported via PostScript Custom Page Size, we still
// want to show them, same as Unidrv does.
//
if (pUiData->pwPapers[dwFormIndex] == DMPAPER_CUSTOMSIZE) { pOptParam[dwFormIndex].Flags |= (OPTPF_HIDE | CONSTRAINED_FLAG); continue; }
#endif // PSCRIPT
//
// If the form conflicts with the tray, then don't display it.
//
if (dwFormSelection != OPTION_INDEX_ANY && CheckFeatureOptionConflict(pUiData->ci.pRawData, dwTrayFeatureIndex, dwTraySelection, dwFormFeatureIndex, dwFormSelection)) { pOptParam[dwFormIndex].Flags |= (OPTPF_HIDE | CONSTRAINED_FLAG); } else { pOptParam[dwFormIndex].Flags &= ~(OPTPF_HIDE | CONSTRAINED_FLAG); } }
return pOptType; }
BOOL BPackItemFormTrayTable( IN OUT PUIDATA pUiData )
/*++
Routine Description:
Pack form-to-tray assignment information into treeview item structures so that we can call common UI library.
Arguments:
pUiData - Points to UIDATA structure
Return Value:
TRUE if successful, FALSE otherwise
--*/
{ POPTITEM pOptItem; POPTTYPE pOptType; DWORD dwIndex, dwTrays; PWSTR pTrayName;
dwTrays = pUiData->dwBinNames;
if (dwTrays == 0) { WARNING(("No paper bin available\n")); return TRUE; }
//
// Form-to-tray assignment table
// Tray <-> Form
// ...
VPackOptItemGroupHeader( pUiData, IDS_CPSUI_FORMTRAYASSIGN, IDI_CPSUI_FORMTRAYASSIGN, HELP_INDEX_FORMTRAYASSIGN);
pUiData->dwFormTrayItem = dwTrays; pUiData->dwOptItem += dwTrays;
if (pUiData->pOptItem == NULL) return TRUE;
pUiData->pFormTrayItems = pUiData->pOptItem;
//
// Generate the list of form names
// Each OPTITEM(Tray) has a OPTTYPE.
//
pOptType = BFillFormNameOptType(pUiData);
if (pOptType == NULL) { ERR(("BFillFormNameOptType failed\n")); return FALSE; }
//
// Create an OPTITEM for each tray
//
pTrayName = pUiData->pBinNames ; pOptItem = pUiData->pOptItem;
for (dwIndex=0; dwIndex < dwTrays; dwIndex++) { //
// The tray items cannot share OPTTYPE and OPTPARAMs because
// each tray can contain a different list of forms.
//
pOptType = PAdjustFormNameOptType(pUiData, pOptType, dwIndex);
if (pOptType == NULL) { ERR(("PAdjustFormNameOptParam failed\n")); return FALSE; }
FILLOPTITEM(pOptItem, pOptType, pTrayName, 0, TVITEM_LEVEL2, DMPUB_NONE, FORM_TRAY_ITEM, HELP_INDEX_TRAY_ITEM);
//
// NOTE: hide the first tray if it's AutoSelect
//
if (dwIndex == 0) { PFEATURE pFeature; PINPUTSLOT pInputSlot;
if ((pFeature = GET_PREDEFINED_FEATURE(pUiData->ci.pUIInfo, GID_INPUTSLOT)) && (pInputSlot = PGetIndexedOption(pUiData->ci.pUIInfo, pFeature, 0)) && (pInputSlot->dwPaperSourceID == DMBIN_FORMSOURCE)) { pOptItem->Flags |= (OPTIF_HIDE|OPTIF_DISABLED); } }
pOptItem++; pTrayName += CCHBINNAME; }
pUiData->pOptItem = pOptItem; return TRUE; }
VOID VSetupFormTrayAssignments( IN PUIDATA pUiData )
/*++
Routine Description:
Update the current selection of tray items based on the specified form-to-tray assignment table
Arguments:
pUiData - Pointer to our UIDATA structure
Return Value:
NONE
Note:
We assume the form-tray items are in their default states when this function is called.
--*/
{ POPTITEM pOptItem; POPTPARAM pOptParam; FORM_TRAY_TABLE pFormTrayTable; FINDFORMTRAY FindData; DWORD dwTrayStartIndex, dwTrayIndex, dwFormIndex, dwTrays, dwOptParam; PCOMMONINFO pci; PFEATURE pFeature; PINPUTSLOT pInputSlot; PPAGESIZE pPageSize;
if ((dwTrays = pUiData->dwFormTrayItem) == 0) return;
pci = &pUiData->ci;
pOptItem = pUiData->pFormTrayItems; pOptParam = pOptItem->pOptType->pOptParam; dwOptParam = pOptItem->pOptType->Count;
//
// Initialize the current selection for every tray to be
// "Not Available"
//
for (dwTrayIndex=0; dwTrayIndex < dwTrays; dwTrayIndex++) pOptItem[dwTrayIndex].Sel = -1;
pFormTrayTable = PGetFormTrayTable(pUiData->ci.hPrinter, NULL);
//
// If the form-to-tray assignment information doesn't exist,
// set up the default assignments
//
if (pFormTrayTable == NULL) { PWSTR pwstrDefaultForm = NULL; WCHAR awchBuf[CCHPAPERNAME]; BOOL bMetric = IsMetricCountry();
//
// Get the default formname (Letter or A4) and
// convert it formname to a seleciton index.
//
if (bMetric && (pci->pUIInfo->dwFlags & FLAG_A4_SIZE_EXISTS)) { pwstrDefaultForm = A4_FORMNAME; } else if (!bMetric && (pci->pUIInfo->dwFlags & FLAG_LETTER_SIZE_EXISTS)) { pwstrDefaultForm = LETTER_FORMNAME; } else { if ((pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE)) && (pPageSize = PGetIndexedOption(pci->pUIInfo, pFeature, pFeature->dwDefaultOptIndex)) && LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, awchBuf, CCHPAPERNAME)) { pwstrDefaultForm = &(awchBuf[0]); } }
//
// If we can't find the default form name, we have to use the first option as the default.
//
dwFormIndex = pwstrDefaultForm ? DwFindFormNameIndex(pUiData, pwstrDefaultForm, NULL) : 0 ;
ASSERT(dwFormIndex < dwOptParam);
//
// Set the default formname for each enabled tray
//
for (dwTrayIndex=0; dwTrayIndex < dwTrays; dwTrayIndex++) { if (! (pOptItem[dwTrayIndex].Flags & OPTIF_DISABLED) && ! IS_CONSTRAINED(&pOptItem[dwTrayIndex], dwFormIndex)) { pOptItem[dwTrayIndex].Sel = dwFormIndex; } }
//
// Save the default form-to-tray assignment table to registry.
//
if (HASPERMISSION(pUiData)) BUnpackItemFormTrayTable(pUiData);
return; }
//
// We are here means that the form to tray assignment does exits.
// Iterate thru the form-to-tray assignment table one entry at
// a time and update the current selection of tray items.
//
RESET_FINDFORMTRAY(pFormTrayTable, &FindData);
//
// If we have synthersized the first "AutoSelect" tray, we should skip it
// in following searching through the form to tray assignment table.
//
// (refer to the logic in previous function BPackItemFormTrayTable)
//
dwTrayStartIndex = 0;
if ((pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_INPUTSLOT)) && (pInputSlot = PGetIndexedOption(pci->pUIInfo, pFeature, 0)) && (pInputSlot->dwPaperSourceID == DMBIN_FORMSOURCE)) { dwTrayStartIndex = 1; }
while (BSearchFormTrayTable(pFormTrayTable, NULL, NULL, &FindData)) { //
// Get the next entry in the form-to-tray assignment table
//
for (dwTrayIndex = dwTrayStartIndex; dwTrayIndex < dwTrays; dwTrayIndex++) { //
// found matching tray?
//
if (_wcsicmp(FindData.ptstrTrayName, pOptItem[dwTrayIndex].pName) == EQUAL_STRING) { //
// If the specified tray name is supported, then check
// if the associated form name is supported.
//
for (dwFormIndex=0; dwFormIndex < dwOptParam; dwFormIndex++) { if (_wcsicmp(FindData.ptstrFormName, pOptParam[dwFormIndex].pData) == EQUAL_STRING) { break; } }
if (dwFormIndex == dwOptParam) { WARNING(("Unknown form name: %ws\n", FindData.ptstrFormName)); } else if ((pOptItem[dwTrayIndex].Flags & OPTIF_DISABLED) || IS_CONSTRAINED(&pOptItem[dwTrayIndex], dwFormIndex)) { WARNING(("Conflicting form-tray assignment\n")); } else { //
// If the associated form name is supported,
// then remember the form index.
//
pOptItem[dwTrayIndex].Sel = dwFormIndex; }
break; } }
if (dwTrayIndex == dwTrays) WARNING(("Unknown tray name: %ws\n", FindData.ptstrTrayName)); }
MemFree(pFormTrayTable); }
DWORD DwCollectFormTrayAssignments( IN PUIDATA pUiData, OUT PWSTR pwstrTable )
/*++
Routine Description:
Collect the form-to-tray assignment information and save it to registry.
Arguments:
pUiData - Pointer to our UIDATA structure pwstrTable - Pointer to memory buffer for storing the table NULL if the caller is only interested in the table size
Return Value:
Size of the table bytes, 0 if there is an error.
--*/
{ DWORD dwChars = 0; INT iLength; DWORD dwIndex; POPTPARAM pOptParam; DWORD dwOptItem = pUiData->dwFormTrayItem; POPTITEM pOptItem = pUiData->pFormTrayItems;
for (dwIndex=0; dwIndex < dwOptItem; dwIndex++, pOptItem++) { ASSERT(ISFORMTRAYITEM(pOptItem->UserData));
if ((pOptItem->Flags & OPTIF_DISABLED)) continue;
//
// Get the Tray name
//
iLength = wcslen(pOptItem->pName) + 1; dwChars += iLength;
if (pwstrTable != NULL) { CopyMemory(pwstrTable, pOptItem->pName, iLength * sizeof(WCHAR)); pwstrTable += iLength; }
//
// Form name
//
if (pOptItem->Sel < 0 ) { dwChars++; if (pwstrTable != NULL) *pwstrTable++ = NUL;
continue; }
pOptParam = pOptItem->pOptType->pOptParam + pOptItem->Sel; iLength = wcslen(pOptParam->pData) + 1; dwChars += iLength;
if (pwstrTable != NULL) { CopyMemory(pwstrTable, pOptParam->pData, iLength * sizeof(WCHAR)); pwstrTable += iLength; } }
//
// Append a NUL character at the end of the table
//
dwChars++;
if (pwstrTable != NULL) *pwstrTable = NUL;
//
// Return the table size in bytes
//
return dwChars * sizeof(WCHAR); }
BOOL BUnpackItemFormTrayTable( IN PUIDATA pUiData )
/*++
Routine Description:
Extract form-to-tray assignment information from treeview items
Arguments:
pUiData - Pointer to UIDATA structure
Return Value:
TRUE if successful, FALSE otherwise
--*/
{ PWSTR pwstrTable = NULL; DWORD dwTableSize;
//
// Figure out how much memory we need to store the form-to-tray assignment table
// Assemble the form-to-tray assignment table
// Save the form-to-tray assignment table to registry
//
if ((dwTableSize = DwCollectFormTrayAssignments(pUiData, NULL)) == 0 || (pwstrTable = MemAlloc(dwTableSize)) == NULL || (dwTableSize != DwCollectFormTrayAssignments(pUiData, pwstrTable)) || !BSaveFormTrayTable(pUiData->ci.hPrinter, pwstrTable, dwTableSize)) { ERR(("Couldn't save form-to-tray assignment table\n")); MemFree(pwstrTable); return FALSE; }
#ifndef WINNT_40
//
// Publish list of available forms in the directory service
//
VNotifyDSOfUpdate(pUiData->ci.hPrinter);
#endif // !WINNT_40
MemFree(pwstrTable); return TRUE; }
DWORD DwFindFormNameIndex( IN PUIDATA pUiData, IN PWSTR pFormName, OUT PBOOL pbSupported )
/*++
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 pbSupported - Whether or not the form is suppported
Return Value:
Index of the specified formname in the list.
--*/
{ DWORD dwIndex; PWSTR pName; FORM_INFO_1 *pForm; PFEATURE pFeature; PPAGESIZE pPageSize; WCHAR awchBuf[CCHPAPERNAME]; PCOMMONINFO pci;
if (pbSupported) *pbSupported = TRUE;
if (IS_EMPTY_STRING(pFormName)) return 0;
//
// Check if the name appears in the list
//
pName = pUiData->pFormNames;
for (dwIndex=0; dwIndex < pUiData->dwFormNames; dwIndex++) { if (_wcsicmp(pFormName, pName) == EQUAL_STRING) return dwIndex;
pName += CCHPAPERNAME; }
//
// If the name is not in the list, try to match
// the form to a printer page size
//
pci = (PCOMMONINFO) pUiData;
if ((pForm = MyGetForm(pci->hPrinter, pFormName, 1)) && BFormSupportedOnPrinter(pci, pForm, &dwIndex) && (pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE)) && (pPageSize = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex)) && LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, awchBuf, CCHPAPERNAME)) { pName = pUiData->pFormNames;
for (dwIndex = 0; dwIndex < pUiData->dwFormNames; dwIndex++) { if (_wcsicmp(awchBuf, pName) == EQUAL_STRING) { MemFree(pForm); return dwIndex; }
pName += CCHPAPERNAME; } }
MemFree(pForm);
//
// The specified form is not supported on the printer.
// Select the first available form.
//
if (pbSupported) *pbSupported = FALSE;
return 0; }
|