|
|
/*++
Copyright (c) 2000 Microsoft Corporation All rights reserved.
Module Name:
psoemhlp.c
Abstract:
PostScript helper functions for OEM UI plugins
HSetOptions
Author:
Feng Yue (fengy)
8/24/2000 fengy Completed with support of both PPD and driver features. 7/21/2000 fengy Created it with function framework.
--*/
#include "precomp.h"
//
// PS driver's helper functions for OEM UI plugins
//
/*++
Routine Name:
VUpdatePSF_EMFFeatures
Routine Description:
change EMF features' settings to make sure they are in sync with each other
Arguments:
pci - pointer to driver's COMMONINFO structure dwChangedItemID - ID to indicate which item has been changed
Return Value:
None
Last Error:
None
--*/ VOID VUpdatePSF_EMFFeatures( IN PCOMMONINFO pci, IN DWORD dwChangedItemID ) { PDEVMODE pdm = pci->pdm; PPSDRVEXTRA pdmPrivate = pci->pdmPrivate;
//
// (refer to VUpdateEmfFeatureItems and VUnpackDocumentPropertiesItems)
//
if (!((PUIDATA)pci)->bEMFSpooling) { ERR(("VUpdatePSF_EMFFeatures: spooler EMF disabled\n")); return; }
if (dwChangedItemID != METASPOOL_ITEM) { if (!ISSET_MFSPOOL_FLAG(pdmPrivate)) { //
// need to turn driver EMF on to support the EMF feature
//
if (dwChangedItemID == NUP_ITEM) { //
// booklet
//
if (NUPOPTION(pdmPrivate) == BOOKLET_UP) { TERSE(("EMF turned on for BOOKLET_UP\n")); SET_MFSPOOL_FLAG(pdmPrivate); } } else if (dwChangedItemID == REVPRINT_ITEM) { BOOL bReversed = BGetPageOrderFlag(pci);
//
// reverse printing
//
if ((!REVPRINTOPTION(pdmPrivate) && bReversed) || (REVPRINTOPTION(pdmPrivate) && !bReversed)) { TERSE(("EMF turned on for reverse order\n")); SET_MFSPOOL_FLAG(pdmPrivate); } } else if (dwChangedItemID == COPIES_COLLATE_ITEM) { //
// collate
//
if ((pdm->dmFields & DM_COLLATE) && (pdm->dmCollate == DMCOLLATE_TRUE) && !PRINTER_SUPPORTS_COLLATE(pci)) { TERSE(("EMF turned on for collate\n")); SET_MFSPOOL_FLAG(pdmPrivate); } } else { RIP(("unknown dwChangedItemID: %d\n", dwChangedItemID)); } } } else { //
// driver EMF option has being changed
//
if (!ISSET_MFSPOOL_FLAG(pdmPrivate)) { BOOL bReversed = BGetPageOrderFlag(pci);
//
// drier EMF option is turned off, need to handle several EMF features
//
// booklet
//
if (NUPOPTION(pdmPrivate) == BOOKLET_UP) { TERSE(("EMF off, so BOOKLET_UP to ONE_UP\n")); NUPOPTION(pdmPrivate) = ONE_UP; }
//
// collate
//
if ((pdm->dmFields & DM_COLLATE) && (pdm->dmCollate == DMCOLLATE_TRUE) && !PRINTER_SUPPORTS_COLLATE(pci)) { TERSE(("EMF off, so collate off\n")); pdm->dmCollate = DMCOLLATE_FALSE;
//
// Update Collate feature option index
//
ChangeOptionsViaID(pci->pInfoHeader, pci->pCombinedOptions, GID_COLLATE, pdm); }
//
// reverse order printing
//
if ((!REVPRINTOPTION(pdmPrivate) && bReversed) || (REVPRINTOPTION(pdmPrivate) && !bReversed)) { TERSE(("EMF off, so reverse %d\n", bReversed)); REVPRINTOPTION(pdmPrivate) = bReversed; } } } }
/*++
Routine Name:
BUpdatePSF_RevPrintAndOutputOrder
Routine Description:
sync up settings between driver synthesized feature %PageOrder and PPD feature *OutputOrder to avoid spooler simulation
Arguments:
pci - pointer to driver's COMMONINFO structure dwChangedItemID - ID to indicate which item has been changed
Return Value:
TRUE if the sync up succeeds FALSE if there is no PPD feature "OutputOrder" or current setting for "OutputOrder" is invalid
Last Error:
None
--*/ BOOL BUpdatePSF_RevPrintAndOutputOrder( IN PCOMMONINFO pci, IN DWORD dwChangedItemID ) { PUIINFO pUIInfo = pci->pUIInfo; PPPDDATA pPpdData; PFEATURE pFeature;
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pci->pInfoHeader); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
//
// refer to VSyncRevPrintAndOutputOrder
//
if (pPpdData && pPpdData->dwOutputOrderIndex != INVALID_FEATURE_INDEX && (pFeature = PGetIndexedFeature(pUIInfo, pPpdData->dwOutputOrderIndex))) { INT iSelection; POPTION pOption; PCSTR pstrOptionName; BOOL bReverse;
//
// "OutputOrder" feature is available. We only recognize the 2 standard options
// "Normal" and "Reverse".
//
iSelection = pci->pCombinedOptions[pPpdData->dwOutputOrderIndex].ubCurOptIndex;
if (iSelection < 2 && (pOption = PGetIndexedOption(pUIInfo, pFeature, iSelection)) && (pstrOptionName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pOption->loKeywordName))) { PPSDRVEXTRA pdmPrivate = pci->pdmPrivate;
if (strcmp(pstrOptionName, "Reverse") == EQUAL_STRING) bReverse = TRUE; else bReverse = FALSE;
if (dwChangedItemID == REVPRINT_ITEM) { //
// reverse printing setting has just being changed. We should change
// "OutputOrder" option if needed to match the requested output order.
//
if ((!REVPRINTOPTION(pdmPrivate) && bReverse) || (REVPRINTOPTION(pdmPrivate) && !bReverse)) { TERSE(("RevPrint change causes OutputOrder to be %d\n", 1 - iSelection)); pci->pCombinedOptions[pPpdData->dwOutputOrderIndex].ubCurOptIndex = (BYTE)(1 - iSelection); } } else { //
// output order setting has just being changed. We should change reverse
// printing option to match the request output order.
//
TERSE(("OutputOrder change causes RevPrint to be %d\n", bReverse)); REVPRINTOPTION(pdmPrivate) = bReverse; }
//
// sync between reverse print and output order succeeeded
//
return TRUE; } }
//
// sync between reverse print and output order failed
//
return FALSE; }
/*++
Routine Name:
VUpdatePSF_BookletAndDuplex
Routine Description:
sync up settings between driver synthesized feature %PagePerSheet and PPD feature *Duplex
Arguments:
pci - pointer to driver's COMMONINFO structure dwChangedItemID - ID to indicate which item has been changed
Return Value:
None
Last Error:
None
--*/ VOID VUpdatePSF_BookletAndDuplex( IN PCOMMONINFO pci, IN DWORD dwChangedItemID ) { PUIINFO pUIInfo = pci->pUIInfo; PFEATURE pDuplexFeature;
//
// refer to VUpdateBookletOption
//
if (pDuplexFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_DUPLEX)) { PDUPLEX pDuplexOption; DWORD dwFeatureIndex, dwOptionIndex; PPSDRVEXTRA pdmPrivate = pci->pdmPrivate;
dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pDuplexFeature); dwOptionIndex = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex; pDuplexOption = PGetIndexedOption(pUIInfo, pDuplexFeature, dwOptionIndex);
if (pDuplexOption && pDuplexOption->dwDuplexID == DMDUP_SIMPLEX && NUPOPTION(pdmPrivate) == BOOKLET_UP) { ASSERT(((PUIDATA)pci)->bEMFSpooling);
if (dwChangedItemID == NUP_ITEM) { DWORD cIndex;
//
// Booklet is enabled - turn duplex on
//
pDuplexOption = PGetIndexedOption(pUIInfo, pDuplexFeature, 0);
for (cIndex = 0 ; cIndex < pDuplexFeature->Options.dwCount; cIndex++) { if (pDuplexOption->dwDuplexID != DMDUP_SIMPLEX) { TERSE(("Booklet change causes Duplex to be %d\n", cIndex)); pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex = (BYTE)cIndex; break; }
pDuplexOption++; } } else { ASSERT(dwChangedItemID == DUPLEX_ITEM);
//
// Duplex is turned off, so disable booklet and set to 2 up.
//
TERSE(("Simplex change causes Booklet to be 2up\n")); NUPOPTION(pdmPrivate) = TWO_UP; } } } }
/*++
Routine Name:
HSetOptions
Routine Description:
set new driver settings for PPD features and driver synthesized features
Arguments:
poemuiobj - pointer to driver context object dwFlags - flags for the set operation pmszFeatureOptionBuf - MULTI_SZ ASCII string containing new settings' feature/option keyword pairs cbin - size in bytes of the pmszFeatureOptionBuf string pdwResult - pointer to the DWORD that will store the result of set operation
Return Value:
S_OK if the set operation succeeds E_INVALIDARG if input pmszFeatureOptionBuf is not in valid MULTI_SZ format, or flag for the set operation is not recognized E_FAIL if the set operation fails
Last Error:
None
--*/ HRESULT HSetOptions( IN POEMUIOBJ poemuiobj, IN DWORD dwFlags, IN PCSTR pmszFeatureOptionBuf, IN DWORD cbIn, OUT PDWORD pdwResult ) { PCOMMONINFO pci = (PCOMMONINFO)poemuiobj; PDEVMODE pdm; PPSDRVEXTRA pdmPrivate; PUIINFO pUIInfo; PPPDDATA pPpdData; PCSTR pszFeature, pszOption; BOOL bPageSizeSet = FALSE, bPrinterSticky, bNoConflict; INT iMode; LAYOUT iOldLayout;
//
// do some validation on the input parameters
//
if (!BValidMultiSZString(pmszFeatureOptionBuf, cbIn, TRUE)) { ERR(("Set: invalid MULTI_SZ input param\n")); return E_INVALIDARG; }
if (!(dwFlags & SETOPTIONS_FLAG_RESOLVE_CONFLICT) && !(dwFlags & SETOPTIONS_FLAG_KEEP_CONFLICT)) { ERR(("Set: invalid dwFlags %d\n", dwFlags)); return E_INVALIDARG; }
pUIInfo = pci->pUIInfo;
pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pci->pInfoHeader); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
if (pPpdData == NULL) { return E_FAIL; }
pdm = pci->pdm;
bPrinterSticky = ((PUIDATA)pci)->iMode == MODE_PRINTER_STICKY ? TRUE : FALSE;
if (!bPrinterSticky) { ASSERT(pdm); pdmPrivate = (PPSDRVEXTRA)GET_DRIVER_PRIVATE_DEVMODE(pdm); iOldLayout = NUPOPTION(pdmPrivate);
//
// First we need to propagate devmode settings (in case
// plugin has changed it) into option array.
//
// devmode is only valid in non printer-sticky mode. Refer to comments
// in HEnumConstrainedOptions().
//
VFixOptionsArrayWithDevmode(pci); }
//
// Then set each feature specified by plugin.
//
pszFeature = pmszFeatureOptionBuf;
while (*pszFeature) { DWORD cbFeatureKeySize, cbOptionKeySize;
cbFeatureKeySize = strlen(pszFeature) + 1; pszOption = pszFeature + cbFeatureKeySize; cbOptionKeySize = strlen(pszOption) + 1;
//
// Feature or option setting string can't be empty.
//
if (cbFeatureKeySize == 1 || cbOptionKeySize == 1) { ERR(("Set: empty feature or option keyword\n")); goto next_feature; }
if (*pszFeature == PSFEATURE_PREFIX) { PPSFEATURE_ENTRY pEntry, pMatchEntry;
//
// synthesized PS driver feature
//
pMatchEntry = NULL; pEntry = (PPSFEATURE_ENTRY)(&kPSFeatureTable[0]);
while (pEntry->pszPSFeatureName) { if ((*pszFeature == *(pEntry->pszPSFeatureName)) && (strcmp(pszFeature, pEntry->pszPSFeatureName) == EQUAL_STRING)) { pMatchEntry = pEntry; break; }
pEntry++; }
//
// See comments in HEnumConstrainedOptions for following stickiness mode check.
//
if (!pMatchEntry || (bPrinterSticky && !pMatchEntry->bPrinterSticky) || (!bPrinterSticky && pMatchEntry->bPrinterSticky)) { VERBOSE(("Set: invalid or mode-mismatched feature %s\n", pszFeature)); goto next_feature; }
if (pMatchEntry->pfnPSProc) { BOOL bResult;
bResult = (pMatchEntry->pfnPSProc)(pci->hPrinter, pUIInfo, pPpdData, pdm, pci->pPrinterData, pszFeature, pszOption, NULL, 0, NULL, PSFPROC_SETOPTION_MODE);
if (bResult) { //
// PS driver EMF features EMF, PageOrder, Nup need special postprocessing
// to synchronize among EMF features (refer to cpcbDocumentPropertyCallback).
//
if ((*pszFeature == kstrPSFEMF[0]) && (strcmp(pszFeature, kstrPSFEMF) == EQUAL_STRING)) { ASSERT(!bPrinterSticky);
VUpdatePSF_EMFFeatures(pci, METASPOOL_ITEM); } else if ((*pszFeature == kstrPSFPageOrder[0]) && (strcmp(pszFeature, kstrPSFPageOrder) == EQUAL_STRING)) { ASSERT(!bPrinterSticky);
//
// first try to sync between reverse print and output order feature
//
if (!BUpdatePSF_RevPrintAndOutputOrder(pci, REVPRINT_ITEM)) { //
// if that failed, reverse print could force EMF on
//
VUpdatePSF_EMFFeatures(pci, REVPRINT_ITEM); } } else if ((*pszFeature == kstrPSFNup[0]) && (strcmp(pszFeature, kstrPSFNup) == EQUAL_STRING)) { ASSERT(!bPrinterSticky);
if (NUPOPTION(pdmPrivate) == BOOKLET_UP) { if (!((PUIDATA)pci)->bEMFSpooling || !SUPPORTS_DUPLEX(pci)) { //
// booklet is not supported if duplex is constrained by an installable
// feature such as duplex unit not installed or spooler EMF is disabled
// (refer to BPackItemEmfFeatures)
//
ERR(("Set: BOOKLET_UP ignored for %s\n", pszFeature)); NUPOPTION(pdmPrivate) = iOldLayout; } else { //
// Booklet will force EMF on
//
VUpdatePSF_EMFFeatures(pci, NUP_ITEM);
//
// Booklet will also turn duplex on
//
VUpdatePSF_BookletAndDuplex(pci, NUP_ITEM); } } } } else { if (GetLastError() == ERROR_INVALID_PARAMETER) { ERR(("Set: %%-feature handler found invalid option %s for %s\n", pszOption, pszFeature)); } else { ERR(("Set: %%-feature handler failed on %s-%s: %d\n", pszFeature, pszOption, GetLastError())); } } } } else { PFEATURE pFeature; POPTION pOption; DWORD dwFeatureIndex, dwOptionIndex; POPTSELECT pOptionsArray = pci->pCombinedOptions;
//
// PPD *OpenUI feature
//
pFeature = PGetNamedFeature(pUIInfo, pszFeature, &dwFeatureIndex);
//
// See comments in HEnumConstrainedOptions for following stickiness mode check.
//
if (!pFeature || (bPrinterSticky && pFeature->dwFeatureType != FEATURETYPE_PRINTERPROPERTY) || (!bPrinterSticky && pFeature->dwFeatureType == FEATURETYPE_PRINTERPROPERTY)) { VERBOSE(("Set: invalid or mode-mismatched feature %s\n", pszFeature)); goto next_feature; }
//
// Skip GID_LEADINGEDGE, GID_USEHWMARGINS. They are not real PPD *OpenUI features.
// Also skip GID_PAGEREGION, it's only set internally. We don't allow user or plugin
// to set it.
//
if (pFeature->dwFeatureID == GID_PAGEREGION || pFeature->dwFeatureID == GID_LEADINGEDGE || pFeature->dwFeatureID == GID_USEHWMARGINS) { ERR(("Set: skip feature %s\n", pszFeature)); goto next_feature; }
pOption = PGetNamedOption(pUIInfo, pFeature, pszOption, &dwOptionIndex);
if (!pOption) { ERR(("Set: invalid input option %s for feature %s\n", pszOption, pszFeature)); goto next_feature; }
//
// update the option selection
//
pOptionsArray[dwFeatureIndex].ubCurOptIndex = (BYTE)dwOptionIndex;
//
// We don't support pick-many yet.
//
ASSERT(pOptionsArray[dwFeatureIndex].ubNext == NULL_OPTSELECT);
//
// some special postprocessing after the option setting is changed
//
if (pFeature->dwFeatureID == GID_PAGESIZE) { PPAGESIZE pPageSize = (PPAGESIZE)pOption;
ASSERT(!bPrinterSticky);
//
// special handling of PS custom page size
//
// refer to VUnpackDocumentPropertiesItems case FORMNAME_ITEM in docprop.c
//
if (pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE) { pdm->dmFields &= ~(DM_PAPERLENGTH|DM_PAPERWIDTH|DM_FORMNAME); pdm->dmFields |= DM_PAPERSIZE; pdm->dmPaperSize = DMPAPER_CUSTOMSIZE;
LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, pdm->dmFormName, CCHFORMNAME); }
bPageSizeSet = TRUE; } else if (pFeature->dwFeatureID == GID_OUTPUTBIN) { ASSERT(!bPrinterSticky);
//
// output bin change could force EMF on
//
VUpdatePSF_EMFFeatures(pci, REVPRINT_ITEM); } else if (pPpdData->dwOutputOrderIndex != INVALID_FEATURE_INDEX && dwFeatureIndex == pPpdData->dwOutputOrderIndex) { ASSERT(!bPrinterSticky);
//
// output order change causes reverse print change
//
if (!BUpdatePSF_RevPrintAndOutputOrder(pci, UNKNOWN_ITEM)) { ERR(("OutputOrder change syncs RevPrint failed\n")); } } }
next_feature:
pszFeature += cbFeatureKeySize + cbOptionKeySize; }
iMode = bPrinterSticky ? MODE_PRINTER_STICKY : MODE_DOCANDPRINTER_STICKY;
if (dwFlags & SETOPTIONS_FLAG_KEEP_CONFLICT) { iMode |= DONT_RESOLVE_CONFLICT; }
//
// 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.
//
bNoConflict = ResolveUIConflicts(pci->pRawData, pci->pCombinedOptions, MAX_COMBINED_OPTIONS, iMode);
if (pdwResult) { if (dwFlags & SETOPTIONS_FLAG_RESOLVE_CONFLICT) { *pdwResult = bNoConflict ? SETOPTIONS_RESULT_NO_CONFLICT : SETOPTIONS_RESULT_CONFLICT_RESOLVED; } else { *pdwResult = bNoConflict ? SETOPTIONS_RESULT_NO_CONFLICT : SETOPTIONS_RESULT_CONFLICT_REMAINED; } }
if (!bPrinterSticky) { //
// Lastly we need to transfer options array settings back
// to devmode so they are in sync.
//
VOptionsToDevmodeFields(pci, bPageSizeSet);
//
// A few more postprocessing here
//
// collate could force EMF on
//
VUpdatePSF_EMFFeatures(pci, COPIES_COLLATE_ITEM);
//
// simplex could change booklet setting
//
VUpdatePSF_BookletAndDuplex(pci, DUPLEX_ITEM); }
return S_OK; }
|