/*++ Copyright (c) 1996 Microsoft Corporation Module Name: devcaps.c Abstract: This file handles the DrvDeviceCapabilities spooler API. Environment: Win32 subsystem, DriverUI module, user mode Revision History: 02/13/97 -davidx- Implement OEM plugin support. 02/10/97 -davidx- Consistent handling of common printer info. 02/04/97 -davidx- Reorganize driver UI to separate ps and uni DLLs. 07/17/96 -amandan- Created it. --*/ #include "precomp.h" DWORD DwDeviceCapabilities( HANDLE hPrinter, PWSTR pDeviceName, WORD wCapability, PVOID pOutput, LONG cchBufSize, PDEVMODE pdmSrc ) /*++ Routine Description: This function support the querrying of device capabilities It gets the binary data (UIINFO) from the parser and return the requested capability to the caller. Arguments: hPrinter handle to printer object pDeviceName pointer to device name wCapability specifies the requested capability pOutput pointer to output buffer cchBufSize Size of output buffer in number of characters pdmSrc pointer to input devmode Return Value: The capabilities supported and relevant information in pOutput --*/ { DWORD dwOld,dwDrv,dwRet = GDI_ERROR; PDEVMODE pdm; PCOMMONINFO pci; FORM_TRAY_TABLE pFormTrayTable; PFN_OEMDeviceCapabilities pfnOEMDeviceCapabilities; BOOL bEMFSpooling, bNup; #if defined(ADOBE) && defined(PSCRIPT) PDEVMODE pdmPrinter = NULL; PPRINTER_INFO_2 pPrinterInfo2 = NULL; #endif // ADOBE && PSCRIPT // // Load basic printer info // Process devmode information: driver default + input devmode // Fix up options array with public devmode information // Get an updated printer description data instance // #if defined(ADOBE) && defined(PSCRIPT) if (!(pci = PLoadCommonInfo(hPrinter, pDeviceName, 0))) { goto devcaps_exit; } // // Fix bug #25547: PS custom paper size problem with Word. // Word is calling DeviceCapabilities with pdmSrc=NULL. The fix // is limited to the cases of PS driver and NULL pdmSrc in order // to minimize possible app-compat problems. // if (pdmSrc == NULL) { if (!(pPrinterInfo2 = MyGetPrinter(pci->hPrinter, 2))) { goto devcaps_exit; } pdmPrinter = pPrinterInfo2->pDevMode; } if ( #ifndef WINNT_40 ! ( (wCapability != DC_PRINTERMEM && wCapability != DC_DUPLEX && wCapability != DC_COLLATE && wCapability != DC_STAPLE)|| (BFillCommonInfoPrinterData(pci)) ) || #endif ! BFillCommonInfoDevmode(pci, (pdmSrc == NULL) ? pdmPrinter : NULL, pdmSrc) || ! BCombineCommonInfoOptionsArray(pci)) { goto devcaps_exit; } #else if (! (pci = PLoadCommonInfo(hPrinter, pDeviceName, 0)) || #ifndef WINNT_40 ! ( (wCapability != DC_PRINTERMEM && wCapability != DC_DUPLEX && wCapability != DC_COLLATE && wCapability != DC_STAPLE)|| (BFillCommonInfoPrinterData(pci)) ) || #endif ! BFillCommonInfoDevmode(pci, NULL, pdmSrc) || ! BCombineCommonInfoOptionsArray(pci)) { goto devcaps_exit; } #endif // ADOBE && PSCRIPT VFixOptionsArrayWithDevmode(pci); (VOID) ResolveUIConflicts(pci->pRawData, pci->pCombinedOptions, MAX_COMBINED_OPTIONS, MODE_DOCUMENT_STICKY); VOptionsToDevmodeFields(pci, TRUE); if (! BUpdateUIInfo(pci)) goto devcaps_exit; pdm = pci->pdm; // // Get spooler EMF cap so that we can report COLLATE and COPIES correctly // VGetSpoolerEmfCaps(pci->hPrinter, &bNup, &bEMFSpooling, 0, NULL); switch (wCapability) { case DC_VERSION: dwRet = pdm->dmSpecVersion; break; case DC_DRIVER: dwRet = pdm->dmDriverVersion; break; case DC_SIZE: dwRet = pdm->dmSize; break; case DC_EXTRA: dwRet = pdm->dmDriverExtra; break; case DC_FIELDS: dwRet = pdm->dmFields; break; case DC_FILEDEPENDENCIES: if (pOutput != NULL) *((PWSTR) pOutput) = NUL; dwRet = 0; break; case DC_COPIES: if (bEMFSpooling && ISSET_MFSPOOL_FLAG(pci->pdmPrivate)) dwRet = max(MAX_COPIES, (SHORT)pci->pUIInfo->dwMaxCopies); else dwRet = pci->pUIInfo->dwMaxCopies; break; case DC_DUPLEX: dwRet = SUPPORTS_DUPLEX(pci) ? 1: 0; break; case DC_TRUETYPE: if (! (pdm->dmFields & DM_TTOPTION)) dwRet = 0; else dwRet = _DwGetFontCap(pci->pUIInfo); break; case DC_ORIENTATION: dwRet = _DwGetOrientationAngle(pci->pUIInfo, pdm); break; case DC_PAPERNAMES: dwRet = DwEnumPaperSizes(pci, pOutput, NULL, NULL, NULL, cchBufSize); break; case DC_PAPERS: dwRet = DwEnumPaperSizes(pci, NULL, pOutput, NULL, NULL, cchBufSize); break; case DC_PAPERSIZE: dwRet = DwEnumPaperSizes(pci, NULL, NULL, pOutput, NULL, cchBufSize); break; case DC_MINEXTENT: case DC_MAXEXTENT: dwRet = DwCalcMinMaxExtent(pci, pOutput, wCapability); break; case DC_BINNAMES: dwRet = DwEnumBinNames(pci, pOutput); break; case DC_BINS: dwRet = DwEnumBins(pci, pOutput); break; case DC_ENUMRESOLUTIONS: dwRet = DwEnumResolutions( pci, pOutput); break; case DC_COLLATE: if (bEMFSpooling && ISSET_MFSPOOL_FLAG(pci->pdmPrivate)) dwRet = DRIVER_SUPPORTS_COLLATE(pci); else dwRet = PRINTER_SUPPORTS_COLLATE(pci); break; // // Following device capabilities are not available on NT4 // #ifndef WINNT_40 case DC_COLORDEVICE: dwRet = IS_COLOR_DEVICE(pci->pUIInfo) ? 1 : 0; break; case DC_NUP: dwRet = DwEnumNupOptions(pci, pOutput); break; case DC_PERSONALITY: dwRet = _DwEnumPersonalities(pci, pOutput); break; case DC_PRINTRATE: if ((dwRet = pci->pUIInfo->dwPrintRate) == 0) dwRet = GDI_ERROR; break; case DC_PRINTRATEUNIT: if ((dwRet = pci->pUIInfo->dwPrintRateUnit) == 0) dwRet = GDI_ERROR; break; case DC_PRINTRATEPPM: if ((dwRet = pci->pUIInfo->dwPrintRatePPM) == 0) dwRet = GDI_ERROR; break; case DC_PRINTERMEM: dwRet = DwGetAvailablePrinterMem(pci); break; case DC_MEDIAREADY: // // Get current form-tray assignment table // if (pFormTrayTable = PGetFormTrayTable(pci->hPrinter, NULL)) { PWSTR pwstr; // // Get list of currently assigned forms. // Notice that DwEnumMediaReady returns currently // form names in place of the original form-tray table. // dwRet = DwEnumMediaReady(pFormTrayTable, NULL); if (dwRet > 0 && pOutput != NULL) { DWORD dwCount; pwstr = pFormTrayTable; dwCount = 0; while (*pwstr) { if ((cchBufSize == UNUSED_PARAM) || (cchBufSize >= CCHPAPERNAME)) { CopyString(pOutput, pwstr, CCHPAPERNAME); pOutput = (PWSTR) pOutput + CCHPAPERNAME; pwstr += wcslen(pwstr) + 1; if (cchBufSize != UNUSED_PARAM) { cchBufSize -= CCHPAPERNAME; } dwCount++; } else { // // Output buffer is not big enough to hold more form names, // so we will just return the number of forms we have filled // into the output buffer so far. // break; } } dwRet = dwCount; } MemFree(pFormTrayTable); } else { PCWSTR pwstrDefault = IsMetricCountry() ? A4_FORMNAME : LETTER_FORMNAME; dwRet = 1; if (pOutput) { if ((cchBufSize == UNUSED_PARAM) || (cchBufSize >= CCHPAPERNAME)) { CopyString(pOutput, pwstrDefault, CCHPAPERNAME); } else { // // Output buffer is not big enough to hold CCHPAPERNAME WCHARs. // dwRet = 0; } } } break; case DC_STAPLE: dwRet = _BSupportStapling(pci); break; case DC_MEDIATYPENAMES: dwRet = DwEnumMediaTypes(pci, pOutput, NULL); break; case DC_MEDIATYPES: dwRet = DwEnumMediaTypes(pci, NULL, pOutput); break; #endif // !WINNT_40 default: SetLastError(ERROR_NOT_SUPPORTED); break; } // // Call OEMDeviceCapabilities entrypoint for each plugin. // If dwRet is GDI_ERROR at this point, it means the system driver // doesn't support the requested device capability or an error // prevented the system driver from handling it. // dwDrv = dwRet; FOREACH_OEMPLUGIN_LOOP(pci) dwOld = dwRet; if (HAS_COM_INTERFACE(pOemEntry)) { if (HComOEMDeviceCapabilities( pOemEntry, &pci->oemuiobj, hPrinter, pDeviceName, wCapability, pOutput, pdm, pOemEntry->pOEMDM, dwOld, &dwRet) == E_NOTIMPL) continue; } else { if (pfnOEMDeviceCapabilities = GET_OEM_ENTRYPOINT(pOemEntry, OEMDeviceCapabilities)) { dwRet = pfnOEMDeviceCapabilities( &pci->oemuiobj, hPrinter, pDeviceName, wCapability, pOutput, pdm, pOemEntry->pOEMDM, dwOld); } } if (dwRet == GDI_ERROR && dwOld != GDI_ERROR) { ERR(("OEMDeviceCapabilities failed for '%ws': %d\n", CURRENT_OEM_MODULE_NAME(pOemEntry), GetLastError())); } END_OEMPLUGIN_LOOP // // The flaw of this API is there is no size associated with the input buffer. // We have to assume that the app is doing the right thing and allocate enough // buffer to hold our values. However, the values can change if the OEM plugins // choose to change the value. We have no way of determine that. // To err on the safe side, we will always ask the app to allocate the larger // of the two values (Unidrv and OEM). When asked the second time to fill out // the buffer, OEM can return the correct values. // if ((pOutput == NULL && dwRet != GDI_ERROR && dwDrv !=GDI_ERROR && dwRet < dwDrv) && (wCapability == DC_PAPERNAMES || wCapability == DC_PAPERS || wCapability == DC_PAPERSIZE || wCapability == DC_BINNAMES || wCapability == DC_BINS || #ifndef WINNT_40 wCapability == DC_NUP || wCapability == DC_PERSONALITY || wCapability == DC_MEDIAREADY || wCapability == DC_MEDIATYPENAMES || wCapability == DC_MEDIATYPES || #endif wCapability == DC_ENUMRESOLUTIONS) ) { // // The size returned by OEM is smaller than what Unidrv needs, so modifies it // if (dwRet == 0) dwRet = GDI_ERROR; else dwRet = dwDrv; } devcaps_exit: if (dwRet == GDI_ERROR) TERSE(("DrvDeviceCapabilities(%d) failed: %d\n", wCapability, GetLastError())); #if defined(ADOBE) && defined(PSCRIPT) if (!pPrinterInfo2) MemFree(pPrinterInfo2); #endif // ADOBE && PSCRIPT VFreeCommonInfo(pci); return dwRet; } DWORD DrvSplDeviceCaps( HANDLE hPrinter, PWSTR pDeviceName, WORD wCapability, PVOID pOutput, DWORD cchBufSize, PDEVMODE pdmSrc ) /*++ Routine Description: This function support the querrying of device capabilities It gets the binary data (UIINFO) from the parser and return the requested capability to the caller. Arguments: hPrinter handle to printer object pDeviceName pointer to device name wCapability specifies the requested capability pOutput pointer to output buffer cchBufSize output buffer size in count of chars pdmSrc pointer to input devmode Return Value: The capabilities supported and relevant information in pOutput --*/ { switch (wCapability) { case DC_PAPERNAMES: #ifndef WINNT_40 case DC_MEDIAREADY: #endif return (DwDeviceCapabilities(hPrinter, pDeviceName, wCapability, pOutput, (LONG)cchBufSize, pdmSrc)); default: return GDI_ERROR; } } DWORD DrvDeviceCapabilities( HANDLE hPrinter, PWSTR pDeviceName, WORD wCapability, PVOID pOutput, PDEVMODE pdmSrc ) /*++ Routine Description: This function support the querrying of device capabilities It gets the binary data (UIINFO) from the parser and return the requested capability to the caller. Arguments: hPrinter handle to printer object pDeviceName pointer to device name wCapability specifies the requested capability pOutput pointer to output buffer pdmSrc pointer to input devmode Return Value: The capabilities supported and relevant information in pOutput --*/ { return (DwDeviceCapabilities(hPrinter, pDeviceName, wCapability, pOutput, UNUSED_PARAM, pdmSrc)); } DWORD DwEnumPaperSizes( PCOMMONINFO pci, PWSTR pPaperNames, PWORD pPapers, PPOINT pPaperSizes, PWORD pPaperFeatures, LONG cchPaperNamesBufSize ) /*++ Routine Description: This function retrieves a list of supported paper sizes Arguments: pci - Points to basic printer information pForms - List of spooler forms dwForms - Number of spooler forms pPaperNames - Buffer for returning supported paper size names pPapers - Buffer for returning supported paper size indices pPaperSizes - Buffer for returning supported paper size dimensions pPaperFeatures - Buffer for returning supported paper size option indices cchPaperNamesBufSize - Size of buffer holding paper names in characters Return Value: Number of paper sizes supported, GDI_ERROR if there is an error. --*/ { PFORM_INFO_1 pForms; DWORD dwCount, dwIndex, dwOptionIndex = 0; #ifdef UNIDRV PFEATURE pFeature; PPAGESIZE pPageSize; PPAGESIZEEX pPageSizeEx; #endif // // Get the list of spooler forms if we haven't done so already // if (pci->pSplForms == NULL) pci->pSplForms = MyEnumForms(pci->hPrinter, 1, &pci->dwSplForms); if (pci->pSplForms == NULL) { ERR(("No spooler forms.\n")); return GDI_ERROR; } // // Go through each form in the forms database // dwCount = 0; pForms = pci->pSplForms; #ifdef UNIDRV pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE); #endif for (dwIndex=0; dwIndex < pci->dwSplForms; dwIndex++, pForms++) { // // If the form is supported on the printer, then // increment the paper size count and collect // requested information // if (! BFormSupportedOnPrinter(pci, pForms, &dwOptionIndex)) continue; dwCount++; // // Return the size of the form in 0.1mm units. // The unit used in FORM_INFO_1 is 0.001mm. // Fill pPaperSizes with the form info supported by the printer // if (pPaperSizes) { pPaperSizes->x = pForms->Size.cx / DEVMODE_PAPER_UNIT; pPaperSizes->y = pForms->Size.cy / DEVMODE_PAPER_UNIT; #ifdef UNIDRV if (pFeature && (pPageSize = PGetIndexedOption(pci->pUIInfo, pFeature, dwOptionIndex)) && (pPageSizeEx = OFFSET_TO_POINTER(pci->pInfoHeader, pPageSize->GenericOption.loRenderOffset)) && (pPageSizeEx->bRotateSize)) { LONG lTemp; lTemp = pPaperSizes->x; pPaperSizes->x = pPaperSizes->y; pPaperSizes->y = lTemp; } #endif // UNIDRV pPaperSizes++; } // // Return the formname. // if (pPaperNames) { if (cchPaperNamesBufSize == UNUSED_PARAM) { CopyString(pPaperNames, pForms->pName, CCHPAPERNAME); pPaperNames += CCHPAPERNAME; } else if (cchPaperNamesBufSize >= CCHPAPERNAME) { CopyString(pPaperNames, pForms->pName, CCHPAPERNAME); pPaperNames += CCHPAPERNAME; cchPaperNamesBufSize -= CCHPAPERNAME; } else { dwCount--; break; } } // // Return one-based index of the form. // if (pPapers) *pPapers++ = (WORD) (dwIndex + DMPAPER_FIRST); // // Return page size feature index // if (pPaperFeatures) *pPaperFeatures++ = (WORD) dwOptionIndex; } #ifdef PSCRIPT { PPPDDATA pPpdData; PPAGESIZE pPageSize; pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pci->pRawData); ASSERT(pPpdData != NULL); if (SUPPORT_FULL_CUSTOMSIZE_FEATURES(pci->pUIInfo, pPpdData) && (pPageSize = PGetCustomPageSizeOption(pci->pUIInfo))) { ASSERT(pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE); dwCount++; if (pPaperSizes) { pPaperSizes->x = pci->pdmPrivate->csdata.dwX / DEVMODE_PAPER_UNIT; pPaperSizes->y = pci->pdmPrivate->csdata.dwY / DEVMODE_PAPER_UNIT; pPaperSizes++; } if (pPaperNames) { if (cchPaperNamesBufSize == UNUSED_PARAM) { LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, pPaperNames, CCHPAPERNAME); pPaperNames += CCHPAPERNAME; } else if (cchPaperNamesBufSize >= CCHPAPERNAME) { LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, pPaperNames, CCHPAPERNAME); pPaperNames += CCHPAPERNAME; cchPaperNamesBufSize -= CCHPAPERNAME; } else dwCount--; } if (pPapers) *pPapers++ = DMPAPER_CUSTOMSIZE; if (pPaperFeatures) *pPaperFeatures++ = (WORD) pci->pUIInfo->dwCustomSizeOptIndex; } } #endif // PSCRIPT return dwCount; } DWORD DwCalcMinMaxExtent( PCOMMONINFO pci, PPOINT pptOutput, WORD wCapability ) /*++ Routine Description: This function retrieves the min and max paper size. Arguments: pci - Points to basic printer information wCapability - What the caller is interested in: DC_MAXEXTENT or DC_MINEXTENT Return Value: Number of paper sizes supported, GDI_ERROR if there is an error. --*/ { PFORM_INFO_1 pForms; DWORD dwCount, dwLoopCnt, dwOptionIndex; LONG lMinX, lMinY, lMaxX, lMaxY, lcx, lcy; #ifdef UNIDRV PFEATURE pFeature; PPAGESIZE pPageSize; PPAGESIZEEX pPageSizeEx; #endif // // Get the list of spooler forms if we haven't done so already // if (pci->pSplForms == NULL) pci->pSplForms = MyEnumForms(pci->hPrinter, 1, &pci->dwSplForms); if (pci->pSplForms == NULL) { ERR(("No spooler forms.\n")); return GDI_ERROR; } // // Go through each form in the forms database // lMinX = lMinY = MAX_LONG; lMaxX = lMaxY = 0; dwCount = 0; pForms = pci->pSplForms; dwLoopCnt = pci->dwSplForms; #ifdef UNIDRV pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE); #endif for ( ; dwLoopCnt--; pForms++) { // // If the form is supported on the printer, then // increment the paper size count and collect // requested information // if (! BFormSupportedOnPrinter(pci, pForms, &dwOptionIndex)) continue; dwCount++; lcx = pForms->Size.cx; lcy = pForms->Size.cy; #ifdef UNIDRV // // Need to swap x, y as we do in DwEnumPaperSizes() if bRotateSize is True. // if (pFeature && (pPageSize = PGetIndexedOption(pci->pUIInfo, pFeature, dwOptionIndex)) && (pPageSizeEx = OFFSET_TO_POINTER(pci->pInfoHeader, pPageSize->GenericOption.loRenderOffset)) && (pPageSizeEx->bRotateSize)) { LONG lTemp; lTemp = lcx; lcx = lcy; lcy = lTemp; } #endif // UNIDRV if (lMinX > lcx) lMinX = lcx; if (lMinY > lcy) lMinY = lcy; if (lMaxX < lcx) lMaxX = lcx; if (lMaxY < lcy) lMaxY = lcy; } #ifdef PSCRIPT // // If the printer supports custom page size, we should // take that into consideration as well. // if (SUPPORT_CUSTOMSIZE(pci->pUIInfo)) { PPPDDATA pPpdData; pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pci->pRawData); ASSERT(pPpdData != NULL); if (lMinX > MINCUSTOMPARAM_WIDTH(pPpdData)) lMinX = MINCUSTOMPARAM_WIDTH(pPpdData); if (lMinY > MINCUSTOMPARAM_HEIGHT(pPpdData)) lMinY = MINCUSTOMPARAM_HEIGHT(pPpdData); if (lMaxX < MAXCUSTOMPARAM_WIDTH(pPpdData)) lMaxX = MAXCUSTOMPARAM_WIDTH(pPpdData); if (lMaxY < MAXCUSTOMPARAM_HEIGHT(pPpdData)) lMaxY = MAXCUSTOMPARAM_HEIGHT(pPpdData); } #endif // PSCRIPT // // Convert from micron to 0.1mm // lMinX /= DEVMODE_PAPER_UNIT; lMinY /= DEVMODE_PAPER_UNIT; lMaxX /= DEVMODE_PAPER_UNIT; lMaxY /= DEVMODE_PAPER_UNIT; // // Return the result as a POINTS structure // if (wCapability == DC_MINEXTENT) { lMinX = min(lMinX, 0x7fff); lMinY = min(lMinY, 0x7fff); return MAKELONG(lMinX, lMinY); } else { lMaxX = min(lMaxX, 0x7fff); lMaxY = min(lMaxY, 0x7fff); return MAKELONG(lMaxX, lMaxY); } } DWORD DwEnumBinNames( PCOMMONINFO pci, PWSTR pBinNames ) /*++ Routine Description: This function retrieves a list of supported paper bins Arguments: pci - Points to basic printer information pBinNames - Buffer for returning paper bin names. It can be NULL if the caller is only interested the number of paper bins supported. Return Value: Number of paper bins supported. --*/ { PFEATURE pFeature; PINPUTSLOT pInputSlot; DWORD dwIndex, dwCount = 0; // // Go through the list of input slots supported by the printer // pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_INPUTSLOT); if ((pFeature != NULL) && (dwCount = pFeature->Options.dwCount) > 0 && (pBinNames != NULL)) { for (dwIndex=0; dwIndex < dwCount; dwIndex++) { pInputSlot = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex); ASSERT(pInputSlot != NULL); // // If the first tray is "*UseFormTrayTable", change its // display name here to be consistent. // if (dwIndex == 0 && pInputSlot->dwPaperSourceID == DMBIN_FORMSOURCE) { LoadString(ghInstance, IDS_TRAY_FORMSOURCE, pBinNames, CCHBINNAME); } else { LOAD_STRING_OPTION_NAME(pci, pInputSlot, pBinNames, CCHBINNAME); } pBinNames += CCHBINNAME; } } return dwCount; } DWORD DwEnumBins( PCOMMONINFO pci, PWORD pBins ) /*++ Routine Description: This function retrieves the number of supported paper bins Arguments: pci - Points to basic printer information pBins - Output buffer for returning paper bin indices. It can be NULL if the caller is only interested the number of paper bins supported. Return Value: Number of paper bins supported. --*/ { PFEATURE pFeature; PINPUTSLOT pInputSlot; DWORD dwIndex, dwCount = 0; // // Go through the list of input slots supported by the printer // pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_INPUTSLOT); if ((pFeature != NULL) && (dwCount = pFeature->Options.dwCount) > 0 && (pBins != NULL)) { for (dwIndex=0; dwIndex < dwCount; dwIndex++) { pInputSlot = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex); ASSERT(pInputSlot != NULL); *pBins++ = (WORD)pInputSlot->dwPaperSourceID; } } return dwCount; } DWORD DwEnumResolutions( PCOMMONINFO pci, PLONG pResolutions ) /*++ Routine Description: This function retrieves a list of supported resolutions. Arguments: pci - Points to basic printer information pResolutions - Returns information about supported resolutions. Two numbers are returned for each resolution option: one for horizontal and the other for vertical. Note that this can be NULL if the caller is only interested in the number of resolutions supported. Return Value: Number of resolutions supported. --*/ { DWORD dwCount, dwIndex; PFEATURE pFeature; PRESOLUTION pResOption; // // Go throught the list of resolutions supported by the printer // pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_RESOLUTION); if (pFeature && pFeature->Options.dwCount > 0) { // // Enumerate all options of the resolution feature // dwCount = pFeature->Options.dwCount; for (dwIndex=0; dwIndex < dwCount; dwIndex++) { pResOption = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex); ASSERT(pResOption != NULL); if (pResolutions != NULL) { *pResolutions++ = pResOption->iXdpi; *pResolutions++ = pResOption->iYdpi; } } } else { // // If no resolution option is available, // return at least one default resolution // dwCount = 1; if (pResolutions != NULL) { pResolutions[0] = pResolutions[1] = _DwGetDefaultResolution(); } } return dwCount; } DWORD DwGetAvailablePrinterMem( PCOMMONINFO pci ) /*++ Routine Description: Find out how much memory is available in the printer Arguments: pci - Points to base printer information Return Value: Amount of memory available in the printer (in KBytes) --*/ { DWORD dwFreeMem; ASSERT(pci->pPrinterData && pci->pCombinedOptions); // // For PSCRIPT, the amount of free memory is stored in // PRINTERDATA.dwFreeMem field. // #ifdef PSCRIPT dwFreeMem = pci->pPrinterData->dwFreeMem; #endif // // For UNIDRV, we need to find out the currently selected // option for GID_MEMOPTION feature. // #ifdef UNIDRV { PFEATURE pFeature; PMEMOPTION pMemOption; DWORD dwIndex; if (! (pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_MEMOPTION))) return GDI_ERROR; dwIndex = GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature); dwIndex = pci->pCombinedOptions[dwIndex].ubCurOptIndex; if (! (pMemOption = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex))) return GDI_ERROR; dwFreeMem = pMemOption->dwInstalledMem; } #endif return dwFreeMem / KBYTES; } DWORD DwEnumMediaReady( FORM_TRAY_TABLE pFormTrayTable, PDWORD pdwResultSize ) /*++ Routine Description: Find the list of forms currently available in the printer Arguments: pFormTrayTable - Points to current form-tray assignment table pdwResultSize - Return the size of the resulting MULTI_SZ (in bytes) Return Value: Number of forms currently available Note: List of supported form names are returned in place of the original form-tray assignment table. Format for form-tray assignment table is: tray-name form-name ... NUL Returned form names are in the form of: form-name ... NUL Duplicate form names are filtered out. --*/ { PWSTR pwstrOutput, pwstrNext, pwstr; DWORD dwCount, dwIndex, dwLen; dwCount = 0; pwstrNext = pwstrOutput = pFormTrayTable; // // Enumerate through each entry of form-tray assignment table // while (*pwstrNext) { // // skip tray name field // pwstrNext += wcslen(pwstrNext) + 1; // // make sure the form name is not a duplicate // pwstr = pFormTrayTable; for (dwIndex=0; dwIndex < dwCount; dwIndex++) { if (_wcsicmp(pwstr, pwstrNext) == EQUAL_STRING) break; pwstr += wcslen(pwstr) + 1; } dwLen = wcslen(pwstrNext) + 1; if (dwIndex == dwCount) { // // if the form name is not a duplicate, nor Not Available, count it // if (*pwstrNext != NUL && *pwstrNext != L'0' && dwLen > 1) { MoveMemory(pwstrOutput, pwstrNext, dwLen * sizeof(WCHAR)); pwstrOutput += dwLen; dwCount++; } } // // go past the form name field // pwstrNext += dwLen; } *pwstrOutput++ = NUL; if (pdwResultSize != NULL) *pdwResultSize = (DWORD)(pwstrOutput - pFormTrayTable) * sizeof(WCHAR); return dwCount; } DWORD DwEnumNupOptions( PCOMMONINFO pci, PDWORD pdwOutput ) /*++ Routine Description: Enumerate the list of supported printer description languages Arguments: pci - Points to common printer info pdwOutput - Points to output buffer Return Value: Number of N-up options supported GDI_ERROR if there is an error --*/ { static CONST DWORD adwNupOptions[] = { 1, 2, 4, 6, 9, 16 }; if (pdwOutput) CopyMemory(pdwOutput, adwNupOptions, sizeof(adwNupOptions)); return sizeof(adwNupOptions) / sizeof(DWORD); } DWORD DwEnumMediaTypes( IN PCOMMONINFO pci, OUT PTSTR pMediaTypeNames, OUT PDWORD pMediaTypes ) /*++ Routine Description: Retrieves the display names and indices of supported media types Arguments: pci - points to common printer information pMediaTypeNames - output buffer for returning supported media type names pMediaTypes - output buffer for returning supported media type indices (Both pMediaTypeNames and pMediaTypes will be NULL if caller if only asking for the number of supported media types.) Return Value: Number of media types supported. --*/ { PFEATURE pFeature; DWORD dwIndex, dwCount; // // This function is used to support both DC_MEDIATYPENAMES and DC_MEDIATYPES. // pMediaTypeNames or pMediaTypes should not both be non-NULL. // ASSERT(pMediaTypeNames == NULL || pMediaTypes == NULL); // // Go through the list of media types supported by the printer // pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_MEDIATYPE); if (pFeature == NULL) { // // Media type feature is not supported by the printer. // return 0; } if (pMediaTypeNames == NULL && pMediaTypes == NULL) { // // caller is only asking for the number of supported media types // return pFeature->Options.dwCount; } dwCount = 0; for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++) { PMEDIATYPE pMediaType; pMediaType = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex); ASSERT(pMediaType != NULL); if (pMediaTypeNames) { if (LOAD_STRING_OPTION_NAME(pci, pMediaType, pMediaTypeNames, CCHMEDIATYPENAME)) { dwCount++; pMediaTypeNames += CCHMEDIATYPENAME; } else { ERR(("LOAD_STRING_OPTION_NAME failed for MediaType option %d\n", dwIndex)); } } else if (pMediaTypes) { *pMediaTypes++ = pMediaType->dwMediaTypeID; dwCount++; } } return dwCount; }