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.
706 lines
15 KiB
706 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devmode.c
|
|
|
|
Abstract:
|
|
|
|
Functions for dealing with devmodes
|
|
|
|
Environment:
|
|
|
|
PCL-XL driver, user and kernel mode
|
|
|
|
Revision History:
|
|
|
|
11/07/95 -davidx-
|
|
Created it.
|
|
|
|
mm/dd/yy -author-
|
|
description
|
|
|
|
--*/
|
|
|
|
#include "xllib.h"
|
|
|
|
|
|
|
|
VOID
|
|
DriverDefaultDevmode(
|
|
PXLDEVMODE pdm,
|
|
PWSTR pDeviceName,
|
|
PMPD pmpd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the driver's default devmode
|
|
|
|
Arguments:
|
|
|
|
pdm - Specifies a buffer for storing driver default devmode
|
|
pDeviceName - Points to device name string
|
|
pmpd - Points to printer description data
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
PRESOPTION pResOption;
|
|
|
|
//
|
|
// Default value for public devmode fields
|
|
//
|
|
|
|
memset(pdm, 0, sizeof(XLDEVMODE));
|
|
|
|
if (pDeviceName != NULL) {
|
|
CopyStringW(pdm->dmPublic.dmDeviceName, pDeviceName, CCHDEVICENAME);
|
|
}
|
|
|
|
pdm->dmPublic.dmDriverVersion = DRIVER_VERSION;
|
|
pdm->dmPublic.dmSpecVersion = DM_SPECVERSION;
|
|
pdm->dmPublic.dmSize = sizeof(DEVMODE);
|
|
pdm->dmPublic.dmDriverExtra = sizeof(DMPRIVATE);
|
|
|
|
pdm->dmPublic.dmFields = DM_ORIENTATION |
|
|
DM_PAPERSIZE |
|
|
DM_SCALE |
|
|
DM_COPIES |
|
|
DM_PRINTQUALITY |
|
|
DM_YRESOLUTION |
|
|
DM_TTOPTION |
|
|
DM_DEFAULTSOURCE;
|
|
|
|
pdm->dmPublic.dmOrientation = DMORIENT_PORTRAIT;
|
|
pdm->dmPublic.dmDuplex = DMDUP_SIMPLEX;
|
|
pdm->dmPublic.dmCollate = DMCOLLATE_FALSE;
|
|
pdm->dmPublic.dmTTOption = DMTT_DOWNLOAD;
|
|
pdm->dmPublic.dmColor = DMCOLOR_MONOCHROME;
|
|
pdm->dmPublic.dmDefaultSource = DMBIN_FORMSOURCE;
|
|
|
|
pdm->dmPublic.dmScale = 100;
|
|
pdm->dmPublic.dmCopies = 1;
|
|
|
|
pResOption = DefaultSelection(MpdResOptions(pmpd), NULL);
|
|
pdm->dmPublic.dmPrintQuality = pResOption->xdpi;
|
|
pdm->dmPublic.dmYResolution = pResOption->ydpi;
|
|
|
|
pdm->dmPublic.dmPaperSize = DMPAPER_LETTER;
|
|
|
|
#ifndef KERNEL_MODE
|
|
|
|
if (IsMetricCountry()) {
|
|
|
|
pdm->dmPublic.dmPaperSize = DMPAPER_A4;
|
|
pdm->dmPrivate.flags |= XLDM_METRIC;
|
|
}
|
|
|
|
#endif
|
|
|
|
if (pmpd->numPlanes > 1) {
|
|
|
|
pdm->dmPublic.dmColor = DMCOLOR_COLOR;
|
|
pdm->dmPublic.dmFields |= DM_COLOR;
|
|
}
|
|
|
|
if (SupportDuplex(pmpd))
|
|
pdm->dmPublic.dmFields |= DM_DUPLEX;
|
|
|
|
if (SupportCollation(pmpd))
|
|
pdm->dmPublic.dmFields |= DM_COLLATE;
|
|
|
|
//
|
|
// Default value for private devmode fields
|
|
//
|
|
|
|
pdm->dmPrivate.signature = DRIVER_SIGNATURE;
|
|
pdm->dmPrivate.mpdChecksum = pmpd->checksum;
|
|
pdm->dmPrivate.optionCount = (WORD) pmpd->cFeatures;
|
|
DefaultPrinterFeatureSelections(pmpd, pdm->dmPrivate.options);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MergeDevmode(
|
|
PXLDEVMODE pdmDest,
|
|
PDEVMODE pdmSrc,
|
|
PMPD pmpd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Merge the source devmode into the destination devmode
|
|
|
|
Arguments:
|
|
|
|
pdmDest - Specifies the destination devmode
|
|
pdmSrc - Specifies the source devmode
|
|
pmpd - Points to printer description data
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if the source devmode is invalid
|
|
|
|
[Note:]
|
|
|
|
pdmDest must point to a valid current-version devmode
|
|
|
|
--*/
|
|
|
|
#define BadDevmode(reason) \
|
|
{ Error(("Invalid DEVMODE: %s\n", reason)); valid = FALSE; }
|
|
|
|
{
|
|
XLDEVMODE dm;
|
|
PDEVMODE pdmIn, pdmOut;
|
|
BOOL valid = TRUE;
|
|
|
|
//
|
|
// If there is no source devmode, levae destination devmode untouched
|
|
//
|
|
|
|
if (pdmSrc == NULL)
|
|
return TRUE;
|
|
|
|
//
|
|
// Convert source devmode to current version
|
|
//
|
|
|
|
Assert(pdmDest->dmPublic.dmSize == sizeof(DEVMODE) &&
|
|
pdmDest->dmPublic.dmDriverExtra == sizeof(DMPRIVATE));
|
|
|
|
memcpy(&dm, pdmDest, sizeof(XLDEVMODE));
|
|
|
|
if (ConvertDevmode(pdmSrc, (PDEVMODE) &dm) <= 0) {
|
|
|
|
Error(("ConvertDevmode failed\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Merge source devmode into destination devmode
|
|
//
|
|
|
|
pdmIn = &dm.dmPublic;
|
|
pdmOut = &pdmDest->dmPublic;
|
|
|
|
//
|
|
// Orientation
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_ORIENTATION) {
|
|
|
|
if (pdmIn->dmOrientation == DMORIENT_PORTRAIT ||
|
|
pdmIn->dmOrientation == DMORIENT_LANDSCAPE)
|
|
{
|
|
pdmOut->dmFields |= DM_ORIENTATION;
|
|
pdmOut->dmOrientation = pdmIn->dmOrientation;
|
|
|
|
} else {
|
|
|
|
BadDevmode("orientation");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Form selection
|
|
//
|
|
|
|
if (CustomDevmodeForm(pdmIn)) {
|
|
|
|
pdmOut->dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH);
|
|
pdmOut->dmPaperLength = pdmIn->dmPaperLength;
|
|
pdmOut->dmPaperWidth = pdmIn->dmPaperWidth;
|
|
}
|
|
|
|
if (pdmIn->dmFields & DM_PAPERSIZE) {
|
|
|
|
pdmOut->dmFields |= DM_PAPERSIZE;
|
|
pdmOut->dmPaperSize = pdmIn->dmPaperSize;
|
|
}
|
|
|
|
if (pdmIn->dmFields & DM_FORMNAME) {
|
|
|
|
pdmOut->dmFields |= DM_FORMNAME;
|
|
CopyStringW(pdmOut->dmFormName, pdmIn->dmFormName, CCHFORMNAME);
|
|
}
|
|
|
|
//
|
|
// Scale factor
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_SCALE) {
|
|
|
|
if (pdmIn->dmScale >= MIN_SCALE && pdmIn->dmScale <= MAX_SCALE) {
|
|
|
|
pdmOut->dmFields |= DM_SCALE;
|
|
pdmOut->dmScale = pdmIn->dmScale;
|
|
|
|
} else {
|
|
|
|
BadDevmode("scale factor");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copies
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_COPIES) {
|
|
|
|
if (pdmIn->dmCopies >= MIN_COPIES && pdmIn->dmCopies <= MAX_COPIES) {
|
|
|
|
pdmOut->dmFields |= DM_COPIES;
|
|
pdmOut->dmCopies = pdmIn->dmCopies;
|
|
|
|
} else {
|
|
|
|
BadDevmode("copy count");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Paper source
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_DEFAULTSOURCE) {
|
|
|
|
if (pdmIn->dmDefaultSource == DMBIN_FORMSOURCE ||
|
|
pdmIn->dmDefaultSource >= DMBIN_USER &&
|
|
pdmIn->dmDefaultSource < DMBIN_USER + MpdInputSlots(pmpd)->count)
|
|
{
|
|
pdmOut->dmFields |= DM_DEFAULTSOURCE;
|
|
pdmOut->dmDefaultSource = pdmIn->dmDefaultSource;
|
|
|
|
} else {
|
|
|
|
BadDevmode("input slot");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resolution
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_YRESOLUTION) {
|
|
|
|
if ((pdmIn->dmFields & DM_PRINTQUALITY) &&
|
|
pdmIn->dmPrintQuality > 0 && pdmIn->dmYResolution > 0)
|
|
{
|
|
pdmOut->dmFields |= DM_PRINTQUALITY|DM_YRESOLUTION;
|
|
pdmOut->dmPrintQuality = pdmIn->dmPrintQuality;
|
|
pdmOut->dmYResolution = pdmIn->dmYResolution;
|
|
|
|
} else {
|
|
|
|
BadDevmode("resolution");
|
|
}
|
|
|
|
} else if (pdmIn->dmFields & DM_PRINTQUALITY) {
|
|
|
|
if (pdmIn->dmPrintQuality > 0) {
|
|
|
|
pdmOut->dmFields |= DM_PRINTQUALITY;
|
|
pdmOut->dmPrintQuality = pdmIn->dmPrintQuality;
|
|
pdmOut->dmFields &= ~DM_YRESOLUTION;
|
|
pdmOut->dmYResolution = 0;
|
|
|
|
} else {
|
|
|
|
BadDevmode("resolution");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Color
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_COLOR) {
|
|
|
|
if (ColorDevice(pmpd) &&
|
|
(pdmIn->dmColor == DMCOLOR_COLOR || pdmIn->dmColor == DMCOLOR_MONOCHROME))
|
|
{
|
|
pdmOut->dmFields |= DM_COLOR;
|
|
pdmOut->dmColor = pdmIn->dmColor;
|
|
|
|
} else {
|
|
|
|
BadDevmode("color");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Duplex
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_DUPLEX) {
|
|
|
|
if (SupportDuplex(pmpd) &&
|
|
(pdmIn->dmDuplex == DMDUP_SIMPLEX ||
|
|
pdmIn->dmDuplex == DMDUP_HORIZONTAL ||
|
|
pdmIn->dmDuplex == DMDUP_VERTICAL))
|
|
{
|
|
pdmOut->dmFields |= DM_DUPLEX;
|
|
pdmOut->dmDuplex = pdmIn->dmDuplex;
|
|
|
|
} else {
|
|
|
|
BadDevmode("duplex");
|
|
}
|
|
}
|
|
|
|
//
|
|
// TrueType font option
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_TTOPTION) {
|
|
|
|
if (pdmIn->dmTTOption == DMTT_BITMAP ||
|
|
pdmIn->dmTTOption == DMTT_DOWNLOAD ||
|
|
pdmIn->dmTTOption == DMTT_SUBDEV ||
|
|
pdmIn->dmTTOption == DMTT_DOWNLOAD_OUTLINE)
|
|
{
|
|
pdmOut->dmFields |= DM_TTOPTION;
|
|
pdmOut->dmTTOption = pdmIn->dmTTOption;
|
|
|
|
} else {
|
|
|
|
BadDevmode("TrueType option");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Collation
|
|
//
|
|
|
|
if (pdmIn->dmFields & DM_COLLATE) {
|
|
|
|
if (SupportCollation(pmpd) &&
|
|
(pdmIn->dmCollate == DMCOLLATE_TRUE || pdmIn->dmCollate == DMCOLLATE_FALSE))
|
|
{
|
|
pdmOut->dmFields |= DM_COLLATE;
|
|
pdmOut->dmCollate = pdmIn->dmCollate;
|
|
|
|
} else {
|
|
|
|
BadDevmode("collate");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Private devmode fields
|
|
//
|
|
|
|
Assert(pdmDest->dmPrivate.signature == DRIVER_SIGNATURE &&
|
|
pdmDest->dmPrivate.mpdChecksum == pmpd->checksum);
|
|
|
|
if (dm.dmPrivate.signature == DRIVER_SIGNATURE) {
|
|
|
|
pdmDest->dmPrivate.flags = dm.dmPrivate.flags;
|
|
|
|
if (dm.dmPrivate.mpdChecksum == pmpd->checksum) {
|
|
|
|
pdmDest->dmPrivate.optionCount = dm.dmPrivate.optionCount;
|
|
memcpy(pdmDest->dmPrivate.options,
|
|
dm.dmPrivate.options,
|
|
min(dm.dmPrivate.optionCount, MAX_FEATURES));
|
|
|
|
} else {
|
|
|
|
BadDevmode("checksum");
|
|
}
|
|
|
|
} else {
|
|
|
|
BadDevmode("signature");
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
GetCombinedDevmode(
|
|
PXLDEVMODE pdmOut,
|
|
PDEVMODE pdmIn,
|
|
HANDLE hPrinter,
|
|
PMPD pmpd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Combine DEVMODE information:
|
|
start with the driver default
|
|
then merge with the system default
|
|
finally merge with the input devmode
|
|
|
|
Arguments:
|
|
|
|
pdmOut - Pointer to the output devmode buffer
|
|
pdmIn - Pointer to an input devmode
|
|
hPrinter - Handle to a printer object
|
|
pmpd - Pointer to printer description data
|
|
|
|
Return Value:
|
|
|
|
TRUE if the input devmode is successfully merged with the default
|
|
devmodes, FALSE if there is an error.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPRINTER_INFO_2 pPrinterInfo2;
|
|
|
|
//
|
|
// Start with driver default devmode
|
|
//
|
|
|
|
DriverDefaultDevmode(pdmOut, NULL, pmpd);
|
|
|
|
//
|
|
// Merge with the system default devmode
|
|
//
|
|
|
|
if (pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) {
|
|
|
|
if (! MergeDevmode(pdmOut, pPrinterInfo2->pDevMode, pmpd)) {
|
|
|
|
Error(("Invalid system default devmode\n"));
|
|
}
|
|
|
|
MemFree(pPrinterInfo2);
|
|
}
|
|
|
|
//
|
|
// Merge with the input devmode if one is provided
|
|
//
|
|
|
|
return MergeDevmode(pdmOut, pdmIn, pmpd);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DevmodeFieldsToOptions(
|
|
PXLDEVMODE pdm,
|
|
DWORD dmFields,
|
|
PMPD pmpd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert information in public devmode fields to printer feature selection indices
|
|
|
|
Arguments:
|
|
|
|
pdm - Points to a devmode structure
|
|
dmFields - Specifies what devmode fields are of interest
|
|
pmpd - Points to printer description data
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
PFEATURE pFeature;
|
|
PBYTE pOptions = pdm->dmPrivate.options;
|
|
WORD selection;
|
|
PWSTR pOptionName;
|
|
|
|
//
|
|
// Collate feature
|
|
//
|
|
|
|
if ((dmFields & DM_COLLATE) && (pFeature = MpdCollate(pmpd))) {
|
|
|
|
pOptionName = (pdm->dmPublic.dmCollate == DMCOLLATE_TRUE) ? L"True" : L"False";
|
|
|
|
if (!FindNamedSelection(pFeature, pOptionName, &selection))
|
|
selection = SELIDX_ANY;
|
|
|
|
pOptions[GetFeatureIndex(pmpd, pFeature)] = (BYTE) selection;
|
|
}
|
|
|
|
//
|
|
// Duplex feature
|
|
//
|
|
|
|
if ((dmFields & DM_DUPLEX) && (pFeature = MpdDuplex(pmpd))) {
|
|
|
|
pOptionName = (pdm->dmPublic.dmDuplex == DMDUP_HORIZONTAL) ? L"Horizontal" :
|
|
(pdm->dmPublic.dmDuplex == DMDUP_VERTICAL) ? L"Vertical" : L"None";
|
|
|
|
if (!FindNamedSelection(pFeature, pOptionName, &selection))
|
|
selection = SELIDX_ANY;
|
|
|
|
pOptions[GetFeatureIndex(pmpd, pFeature)] = (BYTE) selection;
|
|
}
|
|
|
|
//
|
|
// Resolution
|
|
//
|
|
|
|
if ((dmFields & DM_PRINTQUALITY) && (pFeature = MpdResOptions(pmpd))) {
|
|
|
|
if (!FindResolution(pmpd,
|
|
pdm->dmPublic.dmPrintQuality,
|
|
pdm->dmPublic.dmYResolution,
|
|
&selection))
|
|
{
|
|
selection = SELIDX_ANY;
|
|
}
|
|
|
|
pOptions[GetFeatureIndex(pmpd, pFeature)] = (BYTE) selection;
|
|
}
|
|
|
|
//
|
|
// Form selection
|
|
//
|
|
|
|
if ((dmFields & DM_FORMNAME) && (pFeature = MpdPaperSizes(pmpd))) {
|
|
|
|
if (!FindNamedSelection(pFeature, pdm->dmPublic.dmFormName, &selection))
|
|
selection = SELIDX_ANY;
|
|
|
|
pOptions[GetFeatureIndex(pmpd, pFeature)] = (BYTE) selection;
|
|
}
|
|
|
|
//
|
|
// Paper source
|
|
//
|
|
|
|
if ((dmFields & DM_DEFAULTSOURCE) && (pFeature = MpdInputSlots(pmpd))) {
|
|
|
|
if (pdm->dmPublic.dmDefaultSource >= DMBIN_USER)
|
|
selection = pdm->dmPublic.dmDefaultSource - DMBIN_USER;
|
|
else
|
|
selection = SELIDX_ANY;
|
|
|
|
pOptions[GetFeatureIndex(pmpd, pFeature)] = (BYTE) selection;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
PWSTR
|
|
DefaultFormName(
|
|
BOOL metricCountry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the default form name
|
|
|
|
Arguments:
|
|
|
|
metricCountry - Whether the system is running in a metric country
|
|
|
|
Return Value:
|
|
|
|
Pointer to either "Letter" or "A4" depending upon whether
|
|
the system is running in a metric country
|
|
|
|
--*/
|
|
|
|
{
|
|
return metricCountry ? FORMNAME_A4 : FORMNAME_LETTER;
|
|
}
|
|
|
|
|
|
|
|
#ifndef KERNEL_MODE
|
|
|
|
BOOL
|
|
IsMetricCountry(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if the current country is using metric system.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
TRUE if the current country uses metric system, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
INT cChar;
|
|
PWSTR pwstr;
|
|
PSTR pstr;
|
|
LONG lCountryCode;
|
|
BOOL bMetric;
|
|
|
|
//
|
|
// Default to United States
|
|
//
|
|
|
|
bMetric = FALSE;
|
|
pwstr = NULL;
|
|
pstr = NULL;
|
|
|
|
if ((cChar = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, NULL, 0)) > 0 &&
|
|
(pwstr = MemAlloc(cChar * sizeof(WCHAR))) != NULL &&
|
|
(pstr = MemAlloc(cChar * sizeof(CHAR))) != NULL &&
|
|
(cChar = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, pwstr, cChar)) > 0)
|
|
{
|
|
//
|
|
// pwstr now points to a Unicode string representing
|
|
// the country code. Convert it to an integer.
|
|
//
|
|
|
|
UnicodeToMultiByte(pstr, cChar, NULL, pwstr, cChar*sizeof(WCHAR));
|
|
lCountryCode = atol(pstr);
|
|
|
|
//
|
|
// This is the Win31 algorithm based on AT&T international dialing codes.
|
|
//
|
|
|
|
if ((lCountryCode != CTRY_UNITED_STATES) &&
|
|
(lCountryCode != CTRY_CANADA) &&
|
|
(lCountryCode < 50 || lCountryCode >= 60) &&
|
|
(lCountryCode < 500 || lCountryCode >= 600))
|
|
{
|
|
bMetric = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free memory buffers if necessary
|
|
//
|
|
|
|
MemFree(pstr);
|
|
MemFree(pwstr);
|
|
|
|
return bMetric;
|
|
}
|
|
|
|
#endif //!KERNEL_MODE
|