/*++ Copyright (c) 1996 Microsoft Corporation Module Name: ps.c Abstract: This file handles Postscript specific UI options Environment: Win32 subsystem, DriverUI module, user mode Revision History: 02/25/97 -davidx- Finish PS-specific items. 02/04/97 -davidx- Reorganize driver UI to separate ps and uni DLLs. 12/17/96 -amandan- Created it. --*/ #include "precomp.h" #include BOOL BSearchConstraintList(PUIINFO, DWORD, DWORD, DWORD); static CONST WORD ScaleItemInfo[] = { IDS_CPSUI_SCALING, TVITEM_LEVEL1, DMPUB_SCALE, SCALE_ITEM, HELP_INDEX_SCALE, 2, TVOT_UDARROW, IDS_CPSUI_PERCENT, IDI_CPSUI_SCALING, 0, MIN_SCALE, ITEM_INFO_SIGNATURE }; BOOL _BPackItemScale( PUIDATA pUiData ) /*++ Routine Description: Pack scaling option. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error. --*/ { return BPackUDArrowItemTemplate( pUiData, ScaleItemInfo, pUiData->ci.pdm->dmScale, pUiData->ci.pUIInfo->dwMaxScale, NULL); } DWORD _DwEnumPersonalities( PCOMMONINFO pci, PWSTR pwstrOutput ) /*++ Routine Description: Enumerate the list of supported printer description languages Arguments: pci - Points to common printer info pwstrOutput - Points to output buffer Return Value: Number of personalities supported GDI_ERROR if there is an error --*/ { if (pwstrOutput) CopyString(pwstrOutput, TEXT("PostScript"), CCHLANGNAME); return 1; } DWORD _DwGetOrientationAngle( PUIINFO pUIInfo, PDEVMODE pdm ) /*++ Routine Description: Get the orienation angle requested by DrvDeviceCapabilities(DC_ORIENTATION) Arguments: pUIInfo - Pointer to UIINFO pdm - Pointer to DEVMODE Return Value: The angle (90 or 270 or landscape rotation) --*/ { DWORD dwRet; PPSDRVEXTRA pdmPrivate; pdmPrivate = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdm); // // Normal landscape rotates counterclockwise // Rotated landscape rotates clockwise // if (pUIInfo->dwFlags & FLAG_ROTATE90) dwRet = (pdmPrivate->dwFlags & PSDEVMODE_LSROTATE) ? 270 : 90; else dwRet = (pdmPrivate->dwFlags & PSDEVMODE_LSROTATE) ? 90 : 270; return dwRet; } static CONST WORD PSOrientItemInfo[] = { IDS_CPSUI_ORIENTATION, TVITEM_LEVEL1, DMPUB_ORIENTATION, ORIENTATION_ITEM, HELP_INDEX_ORIENTATION, 3, TVOT_3STATES, IDS_CPSUI_PORTRAIT, IDI_CPSUI_PORTRAIT, IDS_CPSUI_LANDSCAPE, IDI_CPSUI_LANDSCAPE, IDS_CPSUI_ROT_LAND, IDI_CPSUI_ROT_LAND, ITEM_INFO_SIGNATURE }; BOOL _BPackOrientationItem( IN OUT PUIDATA pUiData ) /*++ Routine Description: Synthesize the orientation feature for Doc property sheet Arguments: pUiData - Points to UIDATA structure Return Value: TRUE for success and FALSE for failure Note: Always synthesize orienation for PostScript --*/ { PFEATURE pFeature; DWORD dwSelection; // // If there is no predefined orientation feature, we displays it ourselves. // if ((pUiData->ci.pdm->dmFields & DM_ORIENTATION) && (pUiData->ci.pdm->dmOrientation == DMORIENT_LANDSCAPE)) { PPSDRVEXTRA pdmPrivate; pdmPrivate = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pUiData->ci.pdm); dwSelection = pdmPrivate->dwFlags & PSDEVMODE_LSROTATE ? 2 : 1; } else dwSelection = 0; // // Synthesize the feature ourselves // return BPackOptItemTemplate(pUiData, PSOrientItemInfo, dwSelection, NULL); } static CONST WORD PSOutputOptionItemInfo[] = { IDS_PSOUTPUT_OPTION, TVITEM_LEVEL2, DMPUB_NONE, PSOUTPUT_OPTION_ITEM, HELP_INDEX_PSOUTPUT_OPTION, 4, TVOT_LISTBOX, IDS_PSOPT_SPEED, IDI_PSOPT_SPEED, IDS_PSOPT_PORTABILITY, IDI_PSOPT_PORTABILITY, IDS_PSOPT_EPS, IDI_PSOPT_EPS, IDS_PSOPT_ARCHIVE, IDI_PSOPT_ARCHIVE, ITEM_INFO_SIGNATURE }; BOOL BPackItemPSOutputOption( PUIDATA pUiData, PPSDRVEXTRA pdmPrivate ) /*++ Routine Description: Pack PostScript output option item Arguments: pUiData - Points to UIDATA structure pdmPrivate - Points to pscript private devmode Return Value: TRUE if successful, FALSE if there is an error --*/ { DWORD dwSel; switch (pdmPrivate->iDialect) { case PORTABILITY: dwSel = 1; break; case EPS: dwSel = 2; break; case ARCHIVE: dwSel = 3; break; case SPEED: default: dwSel = 0; break; } return BPackOptItemTemplate(pUiData, PSOutputOptionItemInfo, dwSel, NULL); } static CONST WORD PSTTDLFormatItemInfo[] = { IDS_PSTT_DLFORMAT, TVITEM_LEVEL2, DMPUB_NONE, PSTT_DLFORMAT_ITEM, HELP_INDEX_PSTT_DLFORMAT, 4, TVOT_LISTBOX, IDS_TTDL_DEFAULT, IDI_PSTT_DLFORMAT, IDS_TTDL_TYPE1, IDI_PSTT_DLFORMAT, IDS_TTDL_TYPE3, IDI_PSTT_DLFORMAT, IDS_TTDL_TYPE42, IDI_PSTT_DLFORMAT, ITEM_INFO_SIGNATURE }; BOOL BPackItemTTDownloadFormat( PUIDATA pUiData, PPSDRVEXTRA pdmPrivate ) /*++ Routine Description: Pack PostScript TrueType download option item Arguments: pUiData - Points to UIDATA structure pdmPrivate - Points to pscript private devmode Return Value: TRUE if successful, FALSE if there is an error --*/ { DWORD dwSel; BOOL bSupportType42; POPTTYPE pOptType = pUiData->pOptType; bSupportType42 = (pUiData->ci.pUIInfo->dwTTRasterizer == TTRAS_TYPE42); switch (pdmPrivate->iTTDLFmt) { case TYPE_1: dwSel = 1; break; case TYPE_3: dwSel = 2; break; case TYPE_42: dwSel = bSupportType42 ? 3 : 0; break; case TT_DEFAULT: default: dwSel = 0; break; } if (! BPackOptItemTemplate(pUiData, PSTTDLFormatItemInfo, dwSel, NULL)) return FALSE; // // if printer doesn't support Type42, hide Type42 option // if (pOptType && !bSupportType42) pOptType->pOptParam[3].Flags |= OPTPF_HIDE; return TRUE; } static CONST WORD PSLevelItemInfo[] = { IDS_PSLEVEL, TVITEM_LEVEL2, DMPUB_NONE, PSLEVEL_ITEM, HELP_INDEX_SCALE, 2, TVOT_UDARROW, 0, IDI_PSLEVEL, 0, // // Adobe doesn't want to support level 1 // #ifdef ADOBE 2, #else 1, #endif ITEM_INFO_SIGNATURE }; BOOL BPackItemPSLevel( PUIDATA pUiData, PPSDRVEXTRA pdmPrivate ) /*++ Routine Description: Pack PostScript output option item Arguments: pUiData - Points to UIDATA structure pdmPrivate - Points to pscript private devmode Return Value: TRUE if successful, FALSE if there is an error --*/ { DWORD dwSel = pdmPrivate->iPSLevel; DWORD dwLangLevel = pUiData->ci.pUIInfo->dwLangLevel; // // we don't expect language level to be higher than 4 // if (dwLangLevel <= 1) return TRUE; if (dwLangLevel > 4) dwLangLevel = 4; // // make sure the current selection is sensible // if (dwSel == 0 || dwSel > dwLangLevel) dwSel = dwLangLevel; return BPackUDArrowItemTemplate(pUiData, PSLevelItemInfo, dwSel, dwLangLevel, NULL); } static CONST WORD EHandlerItemInfo[] = { IDS_PSERROR_HANDLER, TVITEM_LEVEL2, DMPUB_NONE, PSERROR_HANDLER_ITEM, HELP_INDEX_PSERROR_HANDLER, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; static CONST WORD MirrorItemInfo[] = { IDS_MIRROR, TVITEM_LEVEL2, DMPUB_NONE, MIRROR_ITEM, HELP_INDEX_MIRROR, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; static CONST WORD NegativeItemInfo[] = { IDS_NEGATIVE_PRINT, TVITEM_LEVEL2, DMPUB_NONE, NEGATIVE_ITEM, HELP_INDEX_NEGATIVE, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; static CONST WORD CompressBmpItemInfo[] = { IDS_COMPRESSBMP, TVITEM_LEVEL2, DMPUB_NONE, COMPRESSBMP_ITEM, HELP_INDEX_COMPRESSBMP, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; BOOL _BPackDocumentOptions( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack PostScript specific options such as Job Control etc. Arguments: pUiData - Points to UIDATA structure Return Value: TRUE for success and FALSE for failure --*/ { POPTITEM pOptItem; PPSDRVEXTRA pdmPrivate; DWORD dwFlags; pdmPrivate = pUiData->ci.pdmPrivate; dwFlags = pdmPrivate->dwFlags; pOptItem = pUiData->pOptItem; VPackOptItemGroupHeader(pUiData, IDS_PSOPTIONS, IDI_CPSUI_POSTSCRIPT, HELP_INDEX_PSOPTIONS); if (pOptItem) pOptItem->Flags |= OPTIF_COLLAPSE; return BPackItemPSOutputOption(pUiData, pdmPrivate) && BPackItemTTDownloadFormat(pUiData, pdmPrivate) && BPackItemPSLevel(pUiData, pdmPrivate) && BPackOptItemTemplate( pUiData, EHandlerItemInfo, (dwFlags & PSDEVMODE_EHANDLER) ? 0 : 1, NULL) && (pUiData->ci.pUIInfo->dwLangLevel > 1 || BPackOptItemTemplate( pUiData, CompressBmpItemInfo, (dwFlags & PSDEVMODE_COMPRESSBMP) ? 0 : 1, NULL)) && BPackOptItemTemplate( pUiData, MirrorItemInfo, (dwFlags & PSDEVMODE_MIRROR) ? 0 : 1, NULL) && (IS_COLOR_DEVICE(pUiData->ci.pUIInfo) || BPackOptItemTemplate( pUiData, NegativeItemInfo, (dwFlags & PSDEVMODE_NEG) ? 0 : 1, NULL)); } VOID _VUnpackDocumentOptions( POPTITEM pOptItem, PDEVMODE pdm ) /*++ Routine Description: Extract Postscript devmode information from an OPTITEM Stored it back into Postscript devmode. Arguments: pOptItem - Pointer to an OPTITEM pdm - Pointer to Postscript DEVMODE structure Return Value: None --*/ { PPSDRVEXTRA pdmPrivate; pdmPrivate = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdm); switch (GETUSERDATAITEM(pOptItem->UserData)) { case ORIENTATION_ITEM: pdm->dmFields |= DM_ORIENTATION; pdm->dmOrientation = (pOptItem->Sel == 0) ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE; if (pOptItem->Sel != 2) pdmPrivate->dwFlags &= ~PSDEVMODE_LSROTATE; else pdmPrivate->dwFlags |= PSDEVMODE_LSROTATE; break; case PSOUTPUT_OPTION_ITEM: switch (pOptItem->Sel) { case 1: pdmPrivate->iDialect = PORTABILITY; break; case 2: pdmPrivate->iDialect = EPS; break; case 3: pdmPrivate->iDialect = ARCHIVE; break; case 0: default: pdmPrivate->iDialect = SPEED; break; } break; case PSTT_DLFORMAT_ITEM: switch (pOptItem->Sel) { case 1: pdmPrivate->iTTDLFmt = TYPE_1; break; case 2: pdmPrivate->iTTDLFmt = TYPE_3; break; case 3: pdmPrivate->iTTDLFmt = TYPE_42; break; case 0: default: pdmPrivate->iTTDLFmt = TT_DEFAULT; break; } break; case PSLEVEL_ITEM: pdmPrivate->iPSLevel = pOptItem->Sel; break; case PSERROR_HANDLER_ITEM: if (pOptItem->Sel == 0) pdmPrivate->dwFlags |= PSDEVMODE_EHANDLER; else pdmPrivate->dwFlags &= ~PSDEVMODE_EHANDLER; break; case PSHALFTONE_FREQ_ITEM: case PSHALFTONE_ANGLE_ITEM: // DCR - not implemented yet break; case MIRROR_ITEM: if (pOptItem->Sel == 0) pdmPrivate->dwFlags |= PSDEVMODE_MIRROR; else pdmPrivate->dwFlags &= ~PSDEVMODE_MIRROR; break; case NEGATIVE_ITEM: if (pOptItem->Sel == 0) pdmPrivate->dwFlags |= PSDEVMODE_NEG; else pdmPrivate->dwFlags &= ~PSDEVMODE_NEG; break; case COMPRESSBMP_ITEM: if (pOptItem->Sel == 0) pdmPrivate->dwFlags |= PSDEVMODE_COMPRESSBMP; else pdmPrivate->dwFlags &= ~PSDEVMODE_COMPRESSBMP; break; } } static CONST WORD IgnoreDevFontItemInfo[] = { IDS_USE_DEVFONTS, TVITEM_LEVEL1, DMPUB_NONE, IGNORE_DEVFONT_ITEM, HELP_INDEX_IGNORE_DEVFONT, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; BOOL _BPackFontSubstItems( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack font substitution related items (printer-sticky) Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error --*/ { BOOL bNoDeviceFont; bNoDeviceFont = (pUiData->ci.pPrinterData->dwFlags & PFLAGS_IGNORE_DEVFONT); // // On non-1252 code page systems, gives user the option // to disable all device fonts // // Note: On non-1252 CodePage systems (Cs-Ct-Ja-Ko & Cyr-Grk-Tur, etc), // PScript NT4 had difficulty mapping printer font Encodings to GDI strings. // AdobePS5/PScript5 is supposed to handle these correctly. So Adobe wants // this choice to be suppressed on all code pages. // // Fix MS bug #121883, Adobe bug #235417 // if (FALSE && GetACP() != 1252 && !BPackOptItemTemplate(pUiData, IgnoreDevFontItemInfo, bNoDeviceFont ? 1 : 0, NULL)) { return FALSE; } // // Don't display the font substitution table if device font is disabled // if (bNoDeviceFont) return TRUE; return BPackItemFontSubstTable(pUiData); } static CONST WORD ProtocolItemInfo[] = { IDS_PSPROTOCOL, TVITEM_LEVEL1, DMPUB_NONE, PSPROTOCOL_ITEM, HELP_INDEX_PSPROTOCOL, 4, TVOT_LISTBOX, IDS_PSPROTOCOL_ASCII, IDI_PSPROTOCOL, IDS_PSPROTOCOL_BCP, IDI_PSPROTOCOL, IDS_PSPROTOCOL_TBCP, IDI_PSPROTOCOL, IDS_PSPROTOCOL_BINARY, IDI_PSPROTOCOL, ITEM_INFO_SIGNATURE }; BOOL BPackPSProtocolItem( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack PostScript communication protocol item Arguments: pUiData - Points to UIDATA structure Return Value: TRUE if successful, FALSE if there is an error --*/ { DWORD dwSel; POPTITEM pOptItem; POPTPARAM pOptParam; PUIINFO pUIInfo; pOptItem = pUiData->pOptItem; if (! BPackOptItemTemplate(pUiData, ProtocolItemInfo, 0, NULL)) return FALSE; if (pOptItem) { // // Hide those selections which are not supported on the printer // pOptParam = pOptItem->pOptType->pOptParam; pUIInfo = pUiData->ci.pUIInfo; if (! (pUIInfo->dwProtocols & PROTOCOL_BCP)) pOptParam[1].Flags |= OPTPF_HIDE; if (! (pUIInfo->dwProtocols & PROTOCOL_TBCP)) pOptParam[2].Flags |= OPTPF_HIDE; if (! (pUIInfo->dwProtocols & PROTOCOL_BINARY)) pOptParam[3].Flags |= OPTPF_HIDE; switch (pUiData->ci.pPrinterData->wProtocol) { case PROTOCOL_BCP: dwSel = 1; break; case PROTOCOL_TBCP: dwSel = 2; break; case PROTOCOL_BINARY: dwSel = 3; break; default: dwSel = 0; break; } if (pOptParam[dwSel].Flags & OPTPF_HIDE) pOptItem->Sel = 0; else pOptItem->Sel = dwSel; } return TRUE; } // // We will use different lower limit for Printer VM // based on printer level. The 10th element of this // ItemInfo must be filled with correct lower limit // number before begin used. // static WORD PrinterVMItemInfo[] = { IDS_POSTSCRIPT_VM, TVITEM_LEVEL1, DMPUB_NONE, PRINTER_VM_ITEM, HELP_INDEX_PRINTER_VM, 2, TVOT_UDARROW, IDS_KBYTES, IDI_CPSUI_MEM, 0, 0, ITEM_INFO_SIGNATURE }; static CONST WORD JobTimeoutItemInfo[] = { IDS_JOBTIMEOUT, TVITEM_LEVEL1, DMPUB_NONE, JOB_TIMEOUT_ITEM, HELP_INDEX_JOB_TIMEOUT, 2, TVOT_UDARROW, IDS_SECONDS, IDI_USE_DEFAULT, 0, 0, ITEM_INFO_SIGNATURE }; static CONST WORD WaitTimeoutItemInfo[] = { IDS_WAITTIMEOUT, TVITEM_LEVEL1, DMPUB_NONE, WAIT_TIMEOUT_ITEM, HELP_INDEX_WAIT_TIMEOUT, 2, TVOT_UDARROW, IDS_SECONDS, IDI_USE_DEFAULT, 0, 0, ITEM_INFO_SIGNATURE }; static CONST WORD CtrlDBeforeItemInfo[] = { IDS_CTRLD_BEFORE, TVITEM_LEVEL1, DMPUB_NONE, CTRLD_BEFORE_ITEM, HELP_INDEX_CTRLD_BEFORE, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; static CONST WORD CtrlDAfterItemInfo[] = { IDS_CTRLD_AFTER, TVITEM_LEVEL1, DMPUB_NONE, CTRLD_AFTER_ITEM, HELP_INDEX_CTRLD_AFTER, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; static CONST WORD TrueGrayTextItemInfo[] = { IDS_TRUE_GRAY_TEXT, TVITEM_LEVEL1, DMPUB_NONE, TRUE_GRAY_TEXT_ITEM, HELP_INDEX_TRUE_GRAY_TEXT, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; static CONST WORD TrueGrayGraphItemInfo[] = { IDS_TRUE_GRAY_GRAPH, TVITEM_LEVEL1, DMPUB_NONE, TRUE_GRAY_GRAPH_ITEM, HELP_INDEX_TRUE_GRAY_GRAPH, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; static CONST WORD AddEuroItemInfo[] = { IDS_ADD_EURO, TVITEM_LEVEL1, DMPUB_NONE, ADD_EURO_ITEM, HELP_INDEX_ADD_EURO, 2, TVOT_2STATES, IDS_CPSUI_YES, IDI_CPSUI_YES, IDS_CPSUI_NO, IDI_CPSUI_NO, ITEM_INFO_SIGNATURE }; static CONST WORD MinOutlineItemInfo[] = { IDS_PSMINOUTLINE, TVITEM_LEVEL1, DMPUB_NONE, PSMINOUTLINE_ITEM, HELP_INDEX_PSMINOUTLINE, 2, TVOT_UDARROW, IDS_PIXELS, IDI_USE_DEFAULT, 0, 0, ITEM_INFO_SIGNATURE }; static CONST WORD MaxBitmapItemInfo[] = { IDS_PSMAXBITMAP, TVITEM_LEVEL1, DMPUB_NONE, PSMAXBITMAP_ITEM, HELP_INDEX_PSMAXBITMAP, 2, TVOT_UDARROW, IDS_PIXELS, IDI_USE_DEFAULT, 0, 0, ITEM_INFO_SIGNATURE }; BOOL _BPackPrinterOptions( IN OUT PUIDATA pUiData ) /*++ Routine Description: Pack driver-specific options (printer-sticky) Arguments: pUiData - Points to a UIDATA structure Return Value: TRUE for success and FALSE for failure --*/ { PPRINTERDATA pPrinterData = pUiData->ci.pPrinterData; BOOL rc; // // Fill in the lower limit number of PrinterVMItemInfo // based on printer level. // PrinterVMItemInfo[10] = (pUiData->ci.pUIInfo->dwLangLevel <= 1 ? MIN_FREEMEM_L1 : MIN_FREEMEM_L2) / KBYTES; rc = BPackUDArrowItemTemplate( pUiData, PrinterVMItemInfo, pPrinterData->dwFreeMem / KBYTES, 0x7fff, NULL) && BPackPSProtocolItem(pUiData) && BPackOptItemTemplate( pUiData, CtrlDBeforeItemInfo, (pPrinterData->dwFlags & PFLAGS_CTRLD_BEFORE) ? 0 : 1, NULL) && BPackOptItemTemplate( pUiData, CtrlDAfterItemInfo, (pPrinterData->dwFlags & PFLAGS_CTRLD_AFTER) ? 0 : 1, NULL) && BPackOptItemTemplate( pUiData, TrueGrayTextItemInfo, (pPrinterData->dwFlags & PFLAGS_TRUE_GRAY_TEXT) ? 0 : 1, NULL) && BPackOptItemTemplate( pUiData, TrueGrayGraphItemInfo, (pPrinterData->dwFlags & PFLAGS_TRUE_GRAY_GRAPH) ? 0 : 1, NULL); if (!rc) return FALSE; if (pUiData->ci.pUIInfo->dwLangLevel > 1) { rc = BPackOptItemTemplate( pUiData, AddEuroItemInfo, (pPrinterData->dwFlags & PFLAGS_ADD_EURO) ? 0 : 1, NULL); if (!rc) return FALSE; } return BPackUDArrowItemTemplate( pUiData, JobTimeoutItemInfo, pPrinterData->dwJobTimeout, 0x7fff, NULL) && BPackUDArrowItemTemplate( pUiData, WaitTimeoutItemInfo, pPrinterData->dwWaitTimeout, 0x7fff, NULL) && BPackUDArrowItemTemplate( pUiData, MinOutlineItemInfo, pPrinterData->wMinoutlinePPEM, 0x7fff, NULL) && BPackUDArrowItemTemplate( pUiData, MaxBitmapItemInfo, pPrinterData->wMaxbitmapPPEM, 0x7fff, NULL); } VOID _VUnpackDriverPrnPropItem( PUIDATA pUiData, POPTITEM pOptItem ) /*++ Routine Description: Unpack driver-specific printer property items Arguments: pUiData - Points to our UIDATA structure pOptItem - Specifies the OPTITEM to be unpacked Return Value: NONE --*/ { PPRINTERDATA pPrinterData = pUiData->ci.pPrinterData; switch (GETUSERDATAITEM(pOptItem->UserData)) { case PRINTER_VM_ITEM: if (pUiData->ci.dwFlags & FLAG_USER_CHANGED_FREEMEM) { pPrinterData->dwFreeMem = pOptItem->Sel * KBYTES; } break; case PSPROTOCOL_ITEM: switch (pOptItem->Sel) { case 1: pPrinterData->wProtocol = PROTOCOL_BCP; break; case 2: pPrinterData->wProtocol = PROTOCOL_TBCP; break; case 3: pPrinterData->wProtocol = PROTOCOL_BINARY; break; default: pPrinterData->wProtocol = PROTOCOL_ASCII; break; } break; case CTRLD_BEFORE_ITEM: if (pOptItem->Sel == 0) pPrinterData->dwFlags |= PFLAGS_CTRLD_BEFORE; else pPrinterData->dwFlags &= ~PFLAGS_CTRLD_BEFORE; break; case CTRLD_AFTER_ITEM: if (pOptItem->Sel == 0) pPrinterData->dwFlags |= PFLAGS_CTRLD_AFTER; else pPrinterData->dwFlags &= ~PFLAGS_CTRLD_AFTER; break; case TRUE_GRAY_TEXT_ITEM: if (pOptItem->Sel == 0) pPrinterData->dwFlags |= PFLAGS_TRUE_GRAY_TEXT; else pPrinterData->dwFlags &= ~PFLAGS_TRUE_GRAY_TEXT; break; case TRUE_GRAY_GRAPH_ITEM: if (pOptItem->Sel == 0) pPrinterData->dwFlags |= PFLAGS_TRUE_GRAY_GRAPH; else pPrinterData->dwFlags &= ~PFLAGS_TRUE_GRAY_GRAPH; break; case ADD_EURO_ITEM: if (pOptItem->Sel == 0) pPrinterData->dwFlags |= PFLAGS_ADD_EURO; else pPrinterData->dwFlags &= ~PFLAGS_ADD_EURO; pPrinterData->dwFlags |= PFLAGS_EURO_SET; break; case PSMINOUTLINE_ITEM: pPrinterData->wMinoutlinePPEM = (WORD) pOptItem->Sel; break; case PSMAXBITMAP_ITEM: pPrinterData->wMaxbitmapPPEM = (WORD) pOptItem->Sel; break; } } BOOL BUpdateModelNtfFilename( PCOMMONINFO pci ) /*++ Routine Description: Save model-specific NTF filename under PrinterDriverData registry key for compatibility with the new NT4 driver. Arguments: pci - Points to basic printer information Return Value: TRUE if successful, FALSE if there is an error --*/ { // // Get the list of driver dependent files and // save it in registry for NT4 compatibility // PTSTR ptstr, ptstrNext, ptstrDependentFiles, ptstrCopy, ptstrFileNamesWithoutPath; DWORD dwCharCount = 0; BOOL bResult; if ((ptstrDependentFiles = pci->pDriverInfo3->pDependentFiles) == NULL) { return BSetPrinterDataString(pci->hPrinter, REGVAL_DEPFILES, ptstrDependentFiles, REG_MULTI_SZ); } // // First pass of the MULTI_SZ string to get file names char count // while (*ptstrDependentFiles != NUL) { // // Go the end of current string // ptstr = ptstrDependentFiles + _tcslen(ptstrDependentFiles); ptstrNext = ptstr + 1; dwCharCount++; // for the NUL char of current string // // Search backward for '\' path separator // while (--ptstr >= ptstrDependentFiles) { if (*ptstr == TEXT(PATH_SEPARATOR)) { break; } dwCharCount++; } ptstrDependentFiles = ptstrNext; } dwCharCount++; // for the last NUL of the MULTI_SZ string if ((ptstrFileNamesWithoutPath = MemAllocZ(dwCharCount * sizeof(TCHAR))) == NULL) { ERR(("Memory allocation failed\n")); return FALSE; } // // Second pass of the MULTI_SZ string to copy the file names // ptstrDependentFiles = pci->pDriverInfo3->pDependentFiles; ptstrCopy = ptstrFileNamesWithoutPath; while (*ptstrDependentFiles != NUL) { INT iNameLen; // // Go the end of current string // ptstr = ptstrDependentFiles + _tcslen(ptstrDependentFiles); ptstrNext = ptstr + 1; // // Search backward for '\' path separator // while (--ptstr >= ptstrDependentFiles) { if (*ptstr == TEXT(PATH_SEPARATOR)) { break; } } ptstr++; // point to the char after '\' iNameLen = _tcslen(ptstr); CopyMemory(ptstrCopy, ptstr, iNameLen * sizeof(TCHAR)); ptstrCopy += iNameLen + 1; ptstrDependentFiles = ptstrNext; } bResult = BSetPrinterDataString(pci->hPrinter, REGVAL_DEPFILES, ptstrFileNamesWithoutPath, REG_MULTI_SZ); MemFree(ptstrFileNamesWithoutPath); return bResult; } #ifdef WINNT_40 BOOL BUpdateVMErrorMessageID( PCOMMONINFO pci ) /*++ Routine Description: Save the VM Error message ID calculated from the current user's locale under PrinterDriverData registry key. Arguments: pci - Points to basic printer information Return Value: TRUE if successful, FALSE if there is an error --*/ { DWORD dwVMErrorMessageID = DWGetVMErrorMessageID(); return BSetPrinterDataDWord(pci->hPrinter, REGVAL_VMERRORMESSAGEID, dwVMErrorMessageID); } #endif // WINNT_40 INT _IListDevFontNames( HDC hdc, PWSTR pwstrBuf, INT iSize ) { DWORD dwParam = QUERY_FAMILYNAME; // // Ask the driver graphics module for the list of permanant device fonts // return ExtEscape(hdc, DRIVERESC_QUERY_DEVFONTS, sizeof(dwParam), (PCSTR) &dwParam, iSize, (PSTR) pwstrBuf); } INT_PTR CALLBACK _AboutDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) /*++ Routine Description: Procedure for handling "Printer Properties" proerty sheet page Arguments: hDlg - Identifies the property sheet page message - Specifies the message wParam - Specifies additional message-specific information lParam - Specifies additional message-specific information Return Value: Depends on the value of message parameter --*/ { PUIDATA pUiData; PWSTR pPpdFilename; CHAR achBuf[64] = {0}; CHAR achMsg[136] = {0}; PPDDATA *pPpdData; switch (message) { case WM_INITDIALOG: // // Initialize the About dialog box // pUiData = (PUIDATA) lParam; ASSERT(VALIDUIDATA(pUiData)); if (LoadStringA(ghInstance, IDS_PS_VERSION, achBuf, sizeof(achBuf) - 1)) { #ifdef WINNT_40 if (FAILED(StringCchPrintfA(achMsg, CCHOF(achMsg), "%s (" VER_54DRIVERVERSION_STR ")", achBuf))) #else // WINNT_40 if (FAILED(StringCchPrintfA(achMsg, CCHOF(achMsg), "%s (" VER_PRODUCTVERSION_STR ")", achBuf))) #endif // WINNT_40 { WARNING(("Device Settings About box version string truncated.\n")); } } else { WARNING(("Device Setting About box attempt to load version string failed.\n")); } SetDlgItemTextA(hDlg, IDC_WINNT_VER, achMsg); SetDlgItemText(hDlg, IDC_MODELNAME, pUiData->ci.pDriverInfo3->pName); if (pPpdFilename = pUiData->ci.pDriverInfo3->pDataFile) { if (pPpdFilename = wcsrchr(pPpdFilename, TEXT(PATH_SEPARATOR))) pPpdFilename++; else pPpdFilename = pUiData->ci.pDriverInfo3->pDataFile; SetDlgItemText(hDlg, IDC_PPD_FILENAME, pPpdFilename); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pUiData->ci.pInfoHeader); ASSERT(pPpdData != NULL); StringCchPrintfA(achBuf, CCHOF(achBuf), "%d.%d", HIWORD(pPpdData->dwPpdFilever), LOWORD(pPpdData->dwPpdFilever)); SetDlgItemTextA(hDlg, IDC_PPD_FILEVER, achBuf); } return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } // // Determine whether the printer supports stapling // BOOL _BSupportStapling( PCOMMONINFO pci ) { PFEATURE pFeature, pFeatureY; DWORD dwIndex; BOOL bStapleFeatureExist = FALSE; // // Except for *StapleOrientation (whose None option doesn't mean stapling off), // if any of following stapling keywords appear in the PPD file, we check if that // feature is supported with current installable option selections. // // *StapleLocation // *StapleX // *StapleY // *StapleWhen // // PPD spec says that a PPD file can contain either *StapleLocation or // *StapleX and *StapleY but not both. // if (pFeature = PGetNamedFeature(pci->pUIInfo, "StapleLocation", &dwIndex)) { bStapleFeatureExist = TRUE; if (!_BSupportFeature(pci, GID_UNKNOWN, pFeature)) { return FALSE; } } else if ( (pFeature = PGetNamedFeature(pci->pUIInfo, "StapleX", &dwIndex)) && (pFeatureY = PGetNamedFeature(pci->pUIInfo, "StapleY", &dwIndex)) ) { bStapleFeatureExist = TRUE; if (!_BSupportFeature(pci, GID_UNKNOWN, pFeature) || !_BSupportFeature(pci, GID_UNKNOWN, pFeatureY)) { return FALSE; } } if (pFeature = PGetNamedFeature(pci->pUIInfo, "StapleWhen", &dwIndex)) { bStapleFeatureExist = TRUE; if (!_BSupportFeature(pci, GID_UNKNOWN, pFeature)) { return FALSE; } } // // We didn't find any constraints on the stapling features caused by installable options, // so we will assume the printer can support stapling if any of the standard PPD stapling // keywords are present. // return bStapleFeatureExist || PGetNamedFeature(pci->pUIInfo, "StapleOrientation", &dwIndex) != NULL; } BOOL BFeatureIsConstrained( PUIINFO pUIInfo, PFEATURE pFeature, DWORD dwFeatureIndex, DWORD dwOptionCount, DWORD dwConstraintList, PBYTE aubConstrainedOption, DWORD dwGid ) /*++ Routine Description: Determine whether the particular constraint list constrains feature options. Arguments: pUIInfo - Points to a UIINFO structure pFeature - Points to feature structure to be checked whether constraint or not dwFeatureIndex - index for the feature dwOptionCount - number of options for the feature dwConstraintList - Specifies the constraint list to be searched aubConstrainedOption - Byte array of option constrained flag dwGid - GID_DUPLEX, GID_COLLATE or GID_UNKNOWN to allow feature specific don't cares Return Value: TRUE if the feature is constrained by the constraint list, FALSE otherwise. --*/ { POPTION pOption; DWORD dwOptionIndex; ASSERT(dwOptionCount < MAX_PRINTER_OPTIONS); if (dwConstraintList == NULL_CONSTRAINT) return FALSE; for (dwOptionIndex = 0; dwOptionIndex < dwOptionCount; dwOptionIndex++) { pOption = PGetIndexedOption(pUIInfo, pFeature, dwOptionIndex); ASSERT(pOption != NULL); switch(dwGid) { case GID_COLLATE: // // don't care about constraints for no-collate // if (((PCOLLATE) pOption)->dwCollateID == DMCOLLATE_FALSE) continue; break; case GID_DUPLEX: // // don't care about constraints for non-duplex // if (((PDUPLEX) pOption)->dwDuplexID == DMDUP_SIMPLEX) continue; break; case GID_UNKNOWN: default: // // skip the check for None/False option // if (pFeature->dwNoneFalseOptIndex == dwOptionIndex) continue; break; } if (BSearchConstraintList(pUIInfo, dwConstraintList, dwFeatureIndex, dwOptionIndex)) { aubConstrainedOption[dwOptionIndex] = 1; } // // If one option is unconstrained, the feature is not constrained by the // constraint list // if (!aubConstrainedOption[dwOptionIndex]) return FALSE; } return TRUE; } BOOL _BSupportFeature( PCOMMONINFO pci, DWORD dwGid, PFEATURE pFeatureIn ) /*++ Routine Description: Determine whether the printer supports a feature based on current printer-sticky feature selections. Arguments: pci - Points to basic printer information dwGid - the GID of the feature to check for constraints. (currently only GID_COLLATE or GID_DUPLEX if pFeatureIn is NULL) pFeatureIn - pointer to the feature structure if the feature doesn't have predefined GID_xxx value Return Value: TRUE if feature can be supported, FALSE otherwise. --*/ { POPTSELECT pCombinedOptions = pci->pCombinedOptions; PUIINFO pUIInfo = pci->pUIInfo; PFEATURE pCheckFeature, pFeature; POPTION pOption; BYTE aubConstrainedOption[MAX_PRINTER_OPTIONS]; DWORD dwCheckFeatureIndex, dwCheckOptionCount; DWORD dwFeatureIndex; BYTE ubCurOptIndex, ubNext; if (!pCombinedOptions) return FALSE; if (pFeatureIn) { // // If the input feature pointer is provided, dwGid should be GID_UNKNOWN. // ASSERT(dwGid == GID_UNKNOWN); pCheckFeature = pFeatureIn; } else { // // If no input feature pointer, use dwGid to find the feature. dwGid should be // either GID_DUPLEX or GID_COLLATE. // ASSERT((dwGid == GID_DUPLEX) || (dwGid == GID_COLLATE)); if (!(pCheckFeature = GET_PREDEFINED_FEATURE(pUIInfo, dwGid))) return FALSE; } dwCheckFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pCheckFeature); dwCheckOptionCount = pCheckFeature->Options.dwCount; // // Mark all options of the checked feature as non-constrained. // memset(aubConstrainedOption, 0, sizeof(aubConstrainedOption)); // // Scan the feature list to check if it will be constrained by current selections // if (!(pFeature = OFFSET_TO_POINTER(pUIInfo->pInfoHeader, pUIInfo->loFeatureList))) return FALSE; // // We only care about printer-sticky features // pFeature += pUIInfo->dwDocumentFeatures; for (dwFeatureIndex = pUIInfo->dwDocumentFeatures; dwFeatureIndex < pUIInfo->dwDocumentFeatures + pUIInfo->dwPrinterFeatures; dwFeatureIndex++, pFeature++) { // // If the feature's current selection is not None/False, it may constrain the checked feature // if ((DWORD)pCombinedOptions[dwFeatureIndex].ubCurOptIndex != pFeature->dwNoneFalseOptIndex) { if (BFeatureIsConstrained(pUIInfo, pCheckFeature, dwCheckFeatureIndex, dwCheckOptionCount, pFeature->dwUIConstraintList, aubConstrainedOption, dwGid)) return FALSE; } ubNext = (BYTE)dwFeatureIndex; while (1) { ubCurOptIndex = pCombinedOptions[ubNext].ubCurOptIndex; pOption = PGetIndexedOption(pUIInfo, pFeature, ubCurOptIndex == OPTION_INDEX_ANY ? 0 : ubCurOptIndex); if (pOption && BFeatureIsConstrained(pUIInfo, pCheckFeature, dwCheckFeatureIndex, dwCheckOptionCount, pOption->dwUIConstraintList, aubConstrainedOption, dwGid)) return FALSE; if ((ubNext = pCombinedOptions[ubNext].ubNext) == NULL_OPTSELECT) break; } } // // No constraints found, so the feature can be supported. // return TRUE; } VOID VSyncRevPrintAndOutputOrder( PUIDATA pUiData, POPTITEM pCurItem ) /*++ Routine Description: For PostScript driver, PPD could have "*OpenUI *OutputOrder", which enables user to select "Normal" or "Reverse" output order. In order to avoid spooler performing reverse printing simulation, we will ssync up option selections between REVPRINT_ITEM and "OutputOrder". Arguments: pUiData - Pointer to UIDATA structure pCurItem - Pointer to currently selected option item. It will be non-NULL for REVPRINT_ITEM, and will be NULL otherwise. Return Value: None. --*/ { PUIINFO pUIInfo; PPPDDATA pPpdData; PFEATURE pFeature; POPTION pOption; PCSTR pstrKeywordName; POPTITEM pRevPrintItem, pOutputOrderItem; BOOL bReverse; ASSERT(VALIDUIDATA(pUiData)); pUIInfo = pUiData->ci.pUIInfo; pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER)pUiData->ci.pRawData); ASSERT(pPpdData != NULL); if (pPpdData->dwOutputOrderIndex != INVALID_FEATURE_INDEX && (pOutputOrderItem = PFindOptItemWithKeyword(pUiData, "OutputOrder")) && pOutputOrderItem->Sel < 2 && (pFeature = PGetIndexedFeature(pUIInfo, pPpdData->dwOutputOrderIndex)) && (pOption = PGetIndexedOption(pUIInfo, pFeature, pOutputOrderItem->Sel)) && (pstrKeywordName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pOption->loKeywordName))) { // // "OutputOrder" feature is available. // if (strcmp(pstrKeywordName, "Reverse") == EQUAL_STRING) bReverse = TRUE; else bReverse = FALSE; if (pCurItem) { // // Currently selected item is REVPRINT_ITEM. We should change "OutputOrder" option // if needed to match the requested output order. // if ((pCurItem->Sel == 0 && bReverse) || (pCurItem->Sel == 1 && !bReverse)) { pOutputOrderItem->Sel = 1 - pOutputOrderItem->Sel; pOutputOrderItem->Flags |= OPTIF_CHANGED; // // Save the new settings in the options array // VUnpackDocumentPropertiesItems(pUiData, pOutputOrderItem, 1); // // The change could trigger constraints. // if (ICheckConstraintsDlg(pUiData, pOutputOrderItem, 1, FALSE) == CONFLICT_CANCEL) { // // If there is a conflict and the user clicked CANCEL, // we need to restore the origianl selection. // pCurItem->Sel = 1 - pCurItem->Sel; pCurItem->Flags |= OPTIF_CHANGED; VUnpackDocumentPropertiesItems(pUiData, pCurItem, 1); pOutputOrderItem->Sel = 1 - pOutputOrderItem->Sel; pOutputOrderItem->Flags |= OPTIF_CHANGED; VUnpackDocumentPropertiesItems(pUiData, pOutputOrderItem, 1); } } } else { // // Sync up REVPRINT_ITEM selection based on "OutputOrder" selection. // if ((pRevPrintItem = PFindOptItemWithUserData(pUiData, REVPRINT_ITEM)) && ((pRevPrintItem->Sel == 0 && bReverse) || (pRevPrintItem->Sel == 1 && !bReverse))) { pRevPrintItem->Sel = 1 - pRevPrintItem->Sel; pRevPrintItem->Flags |= OPTIF_CHANGED; // // Save the new settings in the options array // VUnpackDocumentPropertiesItems(pUiData, pRevPrintItem, 1); } } } }