mirror of https://github.com/lianthony/NT4.0
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.
636 lines
13 KiB
636 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devcaps.c
|
|
|
|
Abstract:
|
|
|
|
Implementation of DrvDeviceCapabilities
|
|
|
|
[Environment:]
|
|
|
|
Win32 subsystem, PostScript driver, user mode
|
|
|
|
Revision History:
|
|
|
|
08/31/95 -davidx-
|
|
Created it.
|
|
|
|
mm/dd/yy -author-
|
|
description
|
|
|
|
--*/
|
|
|
|
#include "psui.h"
|
|
|
|
|
|
|
|
DWORD
|
|
DrvDeviceCapabilities(
|
|
HANDLE hPrinter,
|
|
PWSTR pDeviceName,
|
|
WORD wCapability,
|
|
PVOID pOutput,
|
|
PDEVMODE pdmSrc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Provides information about the specified device and its capabilities
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Identifies a printer object
|
|
pDeviceName - Points to a null-terminated device name string
|
|
wCapability - Specifies the interested device capability
|
|
pOutput - Points to the output buffer
|
|
pdmSrc - Points to the source devmode structure
|
|
|
|
Return Value:
|
|
|
|
The return value depends on iDevCap.
|
|
|
|
[Note:]
|
|
|
|
Please refer for DDK documentation for more details.
|
|
|
|
--*/
|
|
|
|
#define DevCapsError(errmsg) { DBGERRMSG(errmsg); goto devcaps_exit; }
|
|
|
|
{
|
|
DWORD dwRet = GDI_ERROR;
|
|
HPPD hppd = NULL;
|
|
PDEVMODE pdm = NULL;
|
|
FORM_INFO_1 *pForms;
|
|
DWORD cForms;
|
|
|
|
if (! (hppd = LoadPpdFile(hPrinter, TRUE)))
|
|
DevCapsError("LoadPpdFile");
|
|
|
|
// Allocate memory for devmode data
|
|
|
|
if (! (pdm = (PDEVMODE) MEMALLOC(sizeof(PSDEVMODE))))
|
|
DevCapsError("MEMALLOC");
|
|
|
|
// Fill in a default devmode structure.
|
|
// Modify the default devmode if there is a user supplied one.
|
|
|
|
if (! SetDefaultDevMode(pdm, pDeviceName, hppd, IsMetricCountry()) ||
|
|
! ValidateSetDevMode(pdm, pdmSrc, hppd))
|
|
{
|
|
DevCapsError("SetDefaultDevMode/ValidateSetDevMode");
|
|
}
|
|
|
|
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:
|
|
|
|
dwRet = MAX_COPIES;
|
|
break;
|
|
|
|
case DC_DUPLEX:
|
|
|
|
dwRet = PpdSupportDuplex(hppd) ? 1 : 0;
|
|
break;
|
|
|
|
case DC_TRUETYPE:
|
|
|
|
dwRet = (pdm->dmFields & DM_TTOPTION) ?
|
|
(DCTT_DOWNLOAD | DCTT_SUBDEV) : 0;
|
|
break;
|
|
|
|
case DC_ORIENTATION:
|
|
{
|
|
PRIVATEDEVMODE *pdmPrivate;
|
|
|
|
pdmPrivate = (PRIVATEDEVMODE *) GetPrivateDevMode(pdm);
|
|
|
|
// Normal landscape rotates counterclockwise
|
|
// Rotated landscape rotates clockwise
|
|
|
|
dwRet = (pdmPrivate->dwFlags & PSDEVMODE_LSROTATE) ? 270 : 90;
|
|
}
|
|
break;
|
|
|
|
case DC_PAPERNAMES:
|
|
case DC_PAPERS:
|
|
case DC_PAPERSIZE:
|
|
case DC_MINEXTENT:
|
|
case DC_MAXEXTENT:
|
|
|
|
// Get a list of forms in the forms database
|
|
|
|
pForms = GetDatabaseForms(hPrinter, &cForms);
|
|
|
|
if (pForms == NULL || cForms == 0) {
|
|
|
|
DBGERRMSG("GetDatabaseForms");
|
|
break;
|
|
}
|
|
|
|
if (wCapability == DC_MINEXTENT || wCapability == DC_MAXEXTENT) {
|
|
|
|
dwRet = PsCalcMinMaxExtent(pOutput, hppd, pForms, cForms, wCapability);
|
|
|
|
} else {
|
|
|
|
PWSTR pPaperNames = NULL;
|
|
PWORD pPapers = NULL;
|
|
PPOINT pPaperSizes = NULL;
|
|
|
|
if (wCapability == DC_PAPERNAMES)
|
|
pPaperNames = pOutput;
|
|
else if (wCapability == DC_PAPERS)
|
|
pPapers = pOutput;
|
|
else
|
|
pPaperSizes = pOutput;
|
|
|
|
dwRet = PsEnumPaperSizes(
|
|
hppd, pForms, cForms,
|
|
pPaperNames, pPapers, pPaperSizes, NULL);
|
|
}
|
|
|
|
MEMFREE(pForms);
|
|
break;
|
|
|
|
case DC_BINNAMES:
|
|
|
|
dwRet = PsEnumBinNames(pOutput, hppd);
|
|
|
|
if (dwRet <= 1) {
|
|
DBGMSG(DBG_LEVEL_WARNING, "No input slots!\n");
|
|
}
|
|
break;
|
|
|
|
case DC_BINS:
|
|
|
|
dwRet = PsEnumBins(pOutput, hppd);
|
|
break;
|
|
|
|
case DC_ENUMRESOLUTIONS:
|
|
|
|
dwRet = PsEnumResolutions(pOutput, hppd);
|
|
break;
|
|
}
|
|
|
|
devcaps_exit:
|
|
|
|
// Clean up properly before returning
|
|
|
|
if (hppd != NULL) {
|
|
UnloadPpdFile(hppd);
|
|
}
|
|
|
|
if (pdm != NULL) {
|
|
MEMFREE(pdm);
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
PsEnumPaperSizes(
|
|
HPPD hppd,
|
|
FORM_INFO_1 *pForms,
|
|
DWORD cForms,
|
|
PWSTR pPaperNames,
|
|
PWORD pPapers,
|
|
PPOINT pPaperSizes,
|
|
PWORD pPaperFeatures
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a list of supported paper sizes
|
|
|
|
Arguments:
|
|
|
|
hppd - Handle to our PPD object
|
|
pForms - Pointer to an array of forms from forms database
|
|
cForms - Number of forms in the array
|
|
pPaperNames, pPapers, pPaperSizes, pPaperFeatures -
|
|
Pointer to output buffers
|
|
|
|
Return Value:
|
|
|
|
Number of paper sizes supported.
|
|
GDI_ERROR if an error occurred.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD count = 0;
|
|
DWORD index;
|
|
PRINTERFORM printerForm;
|
|
|
|
ASSERT(pForms != NULL && cForms > 0);
|
|
|
|
// Go through each form in the forms database
|
|
|
|
for (index=0; index < cForms; index++, pForms++) {
|
|
|
|
// If the form is supported on the printer, then
|
|
// increment the paper size count and collect
|
|
// requested information
|
|
|
|
if (FormSupportedOnPrinter(hppd, pForms, &printerForm, TRUE)) {
|
|
|
|
count++;
|
|
|
|
// Return the size of the form in 0.1mm units.
|
|
// The unit used in FORM_INFO_1 is 0.001mm.
|
|
|
|
if (pPaperSizes) {
|
|
|
|
pPaperSizes->x = pForms->Size.cx / 100;
|
|
pPaperSizes->y = pForms->Size.cy / 100;
|
|
pPaperSizes++;
|
|
}
|
|
|
|
// Return the formname.
|
|
|
|
if (pPaperNames) {
|
|
|
|
CopyStringW(pPaperNames, pForms->pName, CCHPAPERNAME);
|
|
pPaperNames += CCHPAPERNAME;
|
|
}
|
|
|
|
// Return one-based index of the form.
|
|
|
|
if (pPapers)
|
|
*pPapers++ = (WORD) index + DMPAPER_FIRST;
|
|
|
|
// Return page size feature index
|
|
|
|
if (pPaperFeatures)
|
|
*pPaperFeatures++ = printerForm.featureIndex;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
PsCalcMinMaxExtent(
|
|
PPOINT pptOutput,
|
|
HPPD hppd,
|
|
FORM_INFO_1 *pForms,
|
|
DWORD cForms,
|
|
WORD wCapability
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves the minimum or maximum paper size extent
|
|
|
|
Arguments:
|
|
|
|
pptOutput - Pointer to a POINT structure for receiving
|
|
the minimum or maximum paper size extent
|
|
hppd - Handle to our PPD object
|
|
pForms - Pointer to an array of forms from forms database
|
|
cForms - Number of forms in the array
|
|
wCapability - What the caller is interested in:
|
|
DC_MAXEXTENT or DC_MINEXTENT
|
|
|
|
Return Value:
|
|
|
|
Number of paper sizes supported. GDI_ERROR if an error occurred.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD count = 0;
|
|
DWORD index;
|
|
LONG minX, minY, maxX, maxY;
|
|
|
|
ASSERT(pForms != NULL && cForms > 0);
|
|
|
|
// Go through each form in the forms database
|
|
|
|
minX = minY = MAX_LONG;
|
|
maxX = maxY = 0;
|
|
|
|
for (index=0; index < cForms; index++, pForms++) {
|
|
|
|
// If the form is supported on the printer, then
|
|
// increment the paper size count and collect
|
|
// requested information
|
|
|
|
if (! FormSupportedOnPrinter(hppd, pForms, NULL, FALSE))
|
|
continue;
|
|
|
|
count++;
|
|
|
|
if (pptOutput == NULL)
|
|
continue;
|
|
|
|
if (minX > pForms->Size.cx)
|
|
minX = pForms->Size.cx;
|
|
|
|
if (minY > pForms->Size.cy)
|
|
minY = pForms->Size.cy;
|
|
|
|
if (maxX < pForms->Size.cx)
|
|
maxX = pForms->Size.cx;
|
|
|
|
if (maxY < pForms->Size.cy)
|
|
maxY = pForms->Size.cy;
|
|
}
|
|
|
|
//
|
|
// Make the behavior consistent with other printer drivers
|
|
//
|
|
|
|
if (wCapability == DC_MINEXTENT) {
|
|
|
|
minX = min(minX, 0x7fff);
|
|
minY = min(minY, 0x7fff);
|
|
|
|
return MAKELONG(minX, minY);
|
|
|
|
} else {
|
|
|
|
maxX = min(maxX, 0x7fff);
|
|
maxY = min(maxY, 0x7fff);
|
|
|
|
return MAKELONG(maxX, maxY);
|
|
}
|
|
|
|
#ifdef _NOT_USED_
|
|
|
|
// If an output buffer is provided, store the calculated
|
|
// minimum and maximum extent information.
|
|
|
|
if (pptOutput != NULL) {
|
|
|
|
// !!! What unit does the caller expect? The documentation
|
|
// doesn't mention anything about this. I assume this should
|
|
// be in the same unit as DEVMODE.dmPaperLength, which is 0.1mm.
|
|
|
|
if (wCapability == DC_MINEXTENT) {
|
|
|
|
pptOutput->x = minX / 100;
|
|
pptOutput->y = minY / 100;
|
|
|
|
} else {
|
|
|
|
pptOutput->x = maxX / 100;
|
|
pptOutput->y = maxY / 100;
|
|
}
|
|
}
|
|
|
|
// !!! Should we take custom page size into consideration?
|
|
|
|
return count;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
PsEnumBinNames(
|
|
PWSTR pBinNames,
|
|
HPPD hppd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a list of supported paper bin names
|
|
|
|
Arguments:
|
|
|
|
pBinNames - Pointer to the output buffer, NULL if the caller
|
|
is only interested the number of paper bins supported.
|
|
hppd - Handle to our PPD object
|
|
|
|
Return Value:
|
|
|
|
Number of paper bins supported. GDI_ERROR if an error occurred.
|
|
|
|
--*/
|
|
|
|
{
|
|
PINPUTSLOT pInputSlot;
|
|
DWORD count;
|
|
|
|
// The first entry is always "Print Manager Setting"
|
|
|
|
count = 1;
|
|
if (pBinNames != NULL) {
|
|
LoadString(ghInstance, IDS_SLOT_FORMSOURCE, pBinNames, CCHBINNAME);
|
|
pBinNames += CCHBINNAME;
|
|
}
|
|
|
|
// Go through the list of input slots supported by the printer
|
|
|
|
pInputSlot = (PINPUTSLOT) UIGROUP_GetOptions(hppd->pInputSlots);
|
|
|
|
while (pInputSlot != NULL) {
|
|
|
|
if (pBinNames != NULL) {
|
|
|
|
CopyStr2Unicode(pBinNames, GetXlatedName(pInputSlot), CCHBINNAME);
|
|
pBinNames += CCHBINNAME;
|
|
}
|
|
|
|
count++;
|
|
pInputSlot = pInputSlot->pNext;
|
|
}
|
|
|
|
// Add the manual feed slot if necessary
|
|
|
|
if (PpdSupportManualFeed(hppd)) {
|
|
|
|
if (pBinNames != NULL)
|
|
CopyStringW(pBinNames, STDSTR_SLOT_MANUAL, CCHBINNAME);
|
|
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
PsEnumBins(
|
|
PWORD pBins,
|
|
HPPD hppd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a list of supported paper bin numbers
|
|
|
|
Arguments:
|
|
|
|
pBins - Pointer to the output buffer, NULL if the caller
|
|
is only interested the number of paper bins supported.
|
|
hppd - Handle to our PPD object
|
|
|
|
Return Value:
|
|
|
|
Number of paper bins supported. GDI_ERROR if an error occurred.
|
|
|
|
--*/
|
|
|
|
{
|
|
PINPUTSLOT pInputSlot;
|
|
DWORD count;
|
|
WORD index;
|
|
|
|
// The first entry is always "Print Manager Setting"
|
|
|
|
count = 1;
|
|
if (pBins != NULL)
|
|
*pBins++ = DMBIN_FORMSOURCE;
|
|
|
|
// Go through the list of input slots supported by the printer
|
|
|
|
pInputSlot = (PINPUTSLOT) UIGROUP_GetOptions(hppd->pInputSlots);
|
|
index = 0;
|
|
|
|
while (pInputSlot != NULL) {
|
|
|
|
if (pBins != NULL)
|
|
*pBins++ = DMBIN_USER + index++;
|
|
|
|
count++;
|
|
pInputSlot = pInputSlot->pNext;
|
|
}
|
|
|
|
// Add the manual feed slot if necessary
|
|
|
|
if (PpdSupportManualFeed(hppd)) {
|
|
|
|
if (pBins != NULL)
|
|
*pBins++ = DMBIN_MANUAL;
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
PsEnumResolutions(
|
|
PLONG pResolutions,
|
|
HPPD hppd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a list of supported resolutions
|
|
|
|
Arguments:
|
|
|
|
pResolutions - Pointer to the output buffer, NULL if the caller
|
|
is only interested the number of paper bins supported.
|
|
hppd - Handle to our PPD object
|
|
|
|
Return Value:
|
|
|
|
Number of resolutions supported. GDI_ERROR if an error occurred.
|
|
|
|
[Note:]
|
|
|
|
Each resolution is represented by two LONGs representing
|
|
horizontal and vertical resolutions (in dpi) respectively.
|
|
|
|
We don't handle anamorphic resolutions, i.e. x-res != y-res.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRESOPTION pResOption;
|
|
LONG resolution;
|
|
DWORD count = 0;
|
|
|
|
// Go throught the list of resolutions supported by the printer
|
|
|
|
pResOption = (PRESOPTION) UIGROUP_GetOptions(hppd->pResOptions);
|
|
|
|
while (pResOption != NULL) {
|
|
|
|
if ((resolution = atol(pResOption->pName)) > 0) {
|
|
|
|
count++;
|
|
if (pResolutions != NULL) {
|
|
*pResolutions++ = resolution;
|
|
*pResolutions++ = resolution;
|
|
}
|
|
}
|
|
|
|
pResOption = pResOption->pNext;
|
|
}
|
|
|
|
// If no resolutions are listed, at least count the default resolution
|
|
|
|
if (count == 0) {
|
|
|
|
count = 1;
|
|
|
|
if (pResolutions != NULL) {
|
|
*pResolutions++ = resolution = PpdDefaultResolution(hppd);
|
|
*pResolutions++ = resolution;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|