You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1503 lines
36 KiB
1503 lines
36 KiB
/*++
|
|
|
|
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;
|
|
}
|