windows-nt/Source/XPSP1/NT/printscan/print/drivers/usermode/driverui/dm.c
2020-09-26 16:20:57 +08:00

661 lines
16 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
dm.c
Abstract:
Devmode related functions used by the driver UI.
Environment:
Win32 subsystem, DriverUI module, user mode
Revision History:
02/05/97 -davidx-
Rewrote it to support OEM plugins among other things.
07/17/96 -amandan-
Created it.
--*/
#include "precomp.h"
//
// This is the devmode version 320 (DM_SPECVERSION)
//
#define DM_SPECVERSION320 0x0320
#define DM_SPECVERSION400 0x0400
#define DM_SPECVERSION401 0x0401
#define DM_SPECVER_BASE DM_SPECVERSION320
#define CCHDEVICENAME320 32
#define CCHFORMNAME320 32
typedef struct _DEVMODE320 {
WCHAR dmDeviceName[CCHDEVICENAME320];
WORD dmSpecVersion;
WORD dmDriverVersion;
WORD dmSize;
WORD dmDriverExtra;
DWORD dmFields;
short dmOrientation;
short dmPaperSize;
short dmPaperLength;
short dmPaperWidth;
short dmScale;
short dmCopies;
short dmDefaultSource;
short dmPrintQuality;
short dmColor;
short dmDuplex;
short dmYResolution;
short dmTTOption;
short dmCollate;
WCHAR dmFormName[CCHFORMNAME320];
WORD dmLogPixels;
DWORD dmBitsPerPel;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
DWORD dmDisplayFlags;
DWORD dmDisplayFrequency;
} DEVMODE320, *PDEVMODE320;
typedef struct _DMEXTRA400 {
DWORD dmICMMethod;
DWORD dmICMIntent;
DWORD dmMediaType;
DWORD dmDitherType;
DWORD dmICCManufacturer;
DWORD dmICCModel;
} DMEXTRA400;
typedef struct _DMEXTRA401 {
DWORD dmPanningWidth;
DWORD dmPanningHeight;
} DMEXTRA401;
#define DM_SIZE320 sizeof(DEVMODE320)
#define DM_SIZE400 (DM_SIZE320 + sizeof(DMEXTRA400))
#define DM_SIZE401 (DM_SIZE400 + sizeof(DMEXTRA401))
VOID
VPatchPublicDevmodeVersion(
IN OUT PDEVMODE pdm
)
/*++
Routine Description:
Patch dmSpecVersion field of the input devmode
based on its dmSize information
Arguments:
pdm - Specifies a devmode to be version-checked
Return Value:
NONE
--*/
{
ASSERT(pdm != NULL);
//
// Check against known devmode sizes
//
switch (pdm->dmSize)
{
case DM_SIZE320:
pdm->dmSpecVersion = DM_SPECVERSION320;
break;
case DM_SIZE400:
pdm->dmSpecVersion = DM_SPECVERSION400;
break;
case DM_SIZE401:
pdm->dmSpecVersion = DM_SPECVERSION401;
break;
}
}
VOID
VSimpleConvertDevmode(
IN PDEVMODE pdmIn,
IN OUT PDEVMODE pdmOut
)
/*++
Routine Description:
Simple-minded devmode conversion function.
Arguments:
pdmIn - Points to an input devmode
pdmOut - Points to an initialized and valid output devmode
Return Value:
NONE
Notes:
This function only relies on values of these 4 fields in pdmOut:
dmSpecVersion
dmDriverVersion
dmSize
dmDriverExtra
All other fields in pdmOut are ignored and zero-filled before
any memory copy occurs.
--*/
{
WORD wSpecVersion, wDriverVersion;
WORD wSize, wDriverExtra;
ASSERT(pdmIn != NULL && pdmOut != NULL);
//
// Copy public devmode fields
//
wSpecVersion = pdmOut->dmSpecVersion;
wDriverVersion = pdmOut->dmDriverVersion;
wSize = pdmOut->dmSize;
wDriverExtra = pdmOut->dmDriverExtra;
ZeroMemory(pdmOut, wSize+wDriverExtra);
CopyMemory(pdmOut, pdmIn, min(wSize, pdmIn->dmSize));
pdmOut->dmSpecVersion = wSpecVersion;
pdmOut->dmDriverVersion = wDriverVersion;
pdmOut->dmSize = wSize;
pdmOut->dmDriverExtra = wDriverExtra;
//
// Copy private devmode fields
//
CopyMemory((PBYTE) pdmOut + pdmOut->dmSize,
(PBYTE) pdmIn + pdmIn->dmSize,
min(wDriverExtra, pdmIn->dmDriverExtra));
VPatchPublicDevmodeVersion(pdmOut);
}
/*++
Routine Name:
VSmartConvertDevmode
Routine Description:
Smart devmode conversion function for CDM_CONVERT. It strictly obeys
the pdmOut's devmode framework (public, fixed-size core private, each
plugin devmode), and do the best to convert data from pdmIn into that
framework. It guarantees that pdmIn's data from a certain section only
goes into the same section in pdmOut, i.e. pdmIn's core private devmode
data won't overrun into pdmOut's plugin devmode section.
Compared with VSimpleConvertDevmode, this function doesn't change the
size of any private devmode section in the original pdmOut. This includes
the sizes of: fixed-size core private devmode and each individual OEM
plugin devmode.
Arguments:
pdmIn - Points to an input devmode
pdmOut - Points to an initialized and valid output devmode
Return Value:
NONE
Note:
These size/version fields are preserved in pdmOut:
dmSpecVersion
dmDriverVersion
dmSize
dmDriverExtra
wSize
wOEMExtra
wVer
each individual OEM plugin's OEM_DMEXTRAHEADER
dwSize
dwSignature
dwVersion
--*/
VOID
VSmartConvertDevmode(
IN PDEVMODE pdmIn,
IN OUT PDEVMODE pdmOut
)
{
PDRIVEREXTRA pdmPrivIn, pdmPrivOut;
WORD wSpecVersion, wDriverVersion;
WORD wSize, wDriverExtra;
WORD wCoreFixIn, wOEMExtraIn;
WORD wCoreFixOut, wOEMExtraOut, wVerOut;
BOOL bMSdm500In = FALSE, bMSdm500Out = FALSE;
ASSERT(pdmIn != NULL && pdmOut != NULL);
//
// First let's determine the version of pdmIn/pdmOut.
//
pdmPrivIn = (PDRIVEREXTRA)GET_DRIVER_PRIVATE_DEVMODE(pdmIn);
pdmPrivOut = (PDRIVEREXTRA)GET_DRIVER_PRIVATE_DEVMODE(pdmOut);
if (pdmIn->dmDriverVersion >= gDriverDMInfo.dmDriverVersion500 &&
pdmIn->dmDriverExtra >= gDriverDMInfo.dmDriverExtra500 &&
pdmPrivIn->dwSignature == gdwDriverDMSignature)
{
wCoreFixIn = pdmPrivIn->wSize;
wOEMExtraIn = pdmPrivIn->wOEMExtra;
if ((wCoreFixIn >= gDriverDMInfo.dmDriverExtra500) &&
((wCoreFixIn + wOEMExtraIn) <= pdmIn->dmDriverExtra))
{
bMSdm500In = TRUE;
}
}
if (pdmOut->dmDriverVersion >= gDriverDMInfo.dmDriverVersion500 &&
pdmOut->dmDriverExtra >= gDriverDMInfo.dmDriverExtra500 &&
pdmPrivOut->dwSignature == gdwDriverDMSignature)
{
wCoreFixOut = pdmPrivOut->wSize;
wOEMExtraOut = pdmPrivOut->wOEMExtra;
if ((wCoreFixOut >= gDriverDMInfo.dmDriverExtra500) &&
((wCoreFixOut + wOEMExtraOut) <= pdmOut->dmDriverExtra))
{
wVerOut = pdmPrivOut->wVer;
bMSdm500Out = TRUE;
}
}
if (!bMSdm500In || !bMSdm500Out)
{
//
// For unknown devmode or MS pre-v5 devmode, there is no
// complexity caused by plugin devmodes, so we will just
// call the simple convert function.
//
VSimpleConvertDevmode(pdmIn, pdmOut);
return;
}
//
// Copy public devmode fields
//
wSpecVersion = pdmOut->dmSpecVersion;
wDriverVersion = pdmOut->dmDriverVersion;
wSize = pdmOut->dmSize;
wDriverExtra = pdmOut->dmDriverExtra;
ZeroMemory(pdmOut, wSize);
CopyMemory(pdmOut, pdmIn, min(wSize, pdmIn->dmSize));
pdmOut->dmSpecVersion = wSpecVersion;
pdmOut->dmDriverVersion = wDriverVersion;
pdmOut->dmSize = wSize;
pdmOut->dmDriverExtra = wDriverExtra;
VPatchPublicDevmodeVersion(pdmOut);
//
// Copy private devmode fields section by section
//
// 1. First copy the fixed-size core section
//
ZeroMemory(pdmPrivOut, wCoreFixOut);
CopyMemory(pdmPrivOut, pdmPrivIn, min(wCoreFixIn, wCoreFixOut));
//
// Restore the size/version fields in core private devmode of pdmOut
//
pdmPrivOut->wSize = wCoreFixOut;
pdmPrivOut->wOEMExtra = wOEMExtraOut;
pdmPrivOut->wVer = wVerOut;
//
// 2. Then copy any OEM plugin devmodes
//
// If pdmOut has no plugin devmodes, then we have no room to copy pdmIn's.
//
// If pdmIn has no plugin devmode, then we have nothing to copy, so we will
// just leave pdmOut's unchanged.
//
// So we only have work to do if both pdmIn and pdmOut have plugin devmodes.
//
if (wOEMExtraIn > 0 && wOEMExtraOut > 0)
{
POEM_DMEXTRAHEADER pOemDMIn, pOemDMOut;
pOemDMIn = (POEM_DMEXTRAHEADER) ((PBYTE)pdmPrivIn + wCoreFixIn);
pOemDMOut = (POEM_DMEXTRAHEADER) ((PBYTE)pdmPrivOut + wCoreFixOut);
//
// Make sure both in and out plugin devmodes blocks are valid before
// we do the conversion. Otherwise, we will leave pdmOut plugin devmodes
// unchanged.
//
if (bIsValidPluginDevmodes(pOemDMIn, (LONG)wOEMExtraIn) &&
bIsValidPluginDevmodes(pOemDMOut, (LONG)wOEMExtraOut))
{
LONG cbInSize = (LONG)wOEMExtraIn;
LONG cbOutSize = (LONG)wOEMExtraOut;
while (cbInSize > 0 && cbOutSize > 0)
{
OEM_DMEXTRAHEADER OemDMHdrIn, OemDMHdrOut;
//
// Copy headers into local buffers
//
CopyMemory(&OemDMHdrIn, pOemDMIn, sizeof(OEM_DMEXTRAHEADER));
CopyMemory(&OemDMHdrOut, pOemDMOut, sizeof(OEM_DMEXTRAHEADER));
if (OemDMHdrIn.dwSize > sizeof(OEM_DMEXTRAHEADER) &&
OemDMHdrOut.dwSize > sizeof(OEM_DMEXTRAHEADER))
{
//
// Zero-fill, then copy over the plugin devmode portion after
// the header structure. Notice that the header structure in
// pOemDMOut is unchanged.
//
ZeroMemory((PBYTE)pOemDMOut + sizeof(OEM_DMEXTRAHEADER),
OemDMHdrOut.dwSize - sizeof(OEM_DMEXTRAHEADER));
CopyMemory((PBYTE)pOemDMOut + sizeof(OEM_DMEXTRAHEADER),
(PBYTE)pOemDMIn + sizeof(OEM_DMEXTRAHEADER),
min(OemDMHdrOut.dwSize - sizeof(OEM_DMEXTRAHEADER),
OemDMHdrIn.dwSize - sizeof(OEM_DMEXTRAHEADER)));
}
cbInSize -= OemDMHdrIn.dwSize;
pOemDMIn = (POEM_DMEXTRAHEADER) ((PBYTE)pOemDMIn + OemDMHdrIn.dwSize);
cbOutSize -= OemDMHdrOut.dwSize;
pOemDMOut = (POEM_DMEXTRAHEADER) ((PBYTE)pOemDMOut + OemDMHdrOut.dwSize);
}
}
}
}
BOOL
BConvertDevmodeOut(
IN PDEVMODE pdmSrc,
IN PDEVMODE pdmIn,
OUT PDEVMODE pdmOut
)
/*++
Routine Description:
This function copy a source devmode to an output devmode buffer.
It should be called by the driver just before the driver returns
to the caller of DrvDocumentPropertySheets.
Arguments:
pdmSrc - pointer to current version of src DEVMODE
pdmIn - pointer to input devmode passed in by the app
pdmOut - pointer to output buffer passed in by the app
Return Value:
TRUE for success
FALSE for failure.
Note:
pdmOut is only the output buffer allocated by the application. It
doesn't necessarily contain any valid devmode content, so we should
not look at any of its fields.
--*/
{
if (pdmOut == NULL)
{
RIP(("Output buffer is NULL.\n"));
return FALSE;
}
//
// Without an input devmode, we'll have to assume the output
// devmode is big enough to hold our current devmode.
//
if (pdmIn == NULL)
{
CopyMemory(pdmOut, pdmSrc, pdmSrc->dmSize + pdmSrc->dmDriverExtra);
return TRUE;
}
//
// If an input devmode is provided, we make sure we don't copy
// anything larger than the input devmode to the output devmode buffer.
// So the private devmode size dmDriverExtra of pdmOut can only shrink
// (when Src private devmode size is smaller), but it will never grow.
//
// This is really dumb because we may end up chopping off tail end of
// public and private devmode fields. But it's neccesary to work with
// ill-behaving apps out there.
//
if (pdmIn->dmSize < pdmSrc->dmSize)
{
pdmOut->dmSpecVersion = pdmIn->dmSpecVersion;
pdmOut->dmSize = pdmIn->dmSize;
}
else
{
pdmOut->dmSpecVersion = pdmSrc->dmSpecVersion;
pdmOut->dmSize = pdmSrc->dmSize;
}
if (pdmIn->dmDriverExtra < pdmSrc->dmDriverExtra)
{
pdmOut->dmDriverVersion = pdmIn->dmDriverVersion;
pdmOut->dmDriverExtra = pdmIn->dmDriverExtra;
}
else
{
pdmOut->dmDriverVersion = pdmSrc->dmDriverVersion;
pdmOut->dmDriverExtra = pdmSrc->dmDriverExtra;
}
VSimpleConvertDevmode(pdmSrc, pdmOut);
return TRUE;
}
BOOL
DrvConvertDevMode(
LPTSTR pPrinterName,
PDEVMODE pdmIn,
PDEVMODE pdmOut,
PLONG pcbNeeded,
DWORD fMode
)
/*++
Routine Description:
This function convert the devmode from previous version.
Arguments:
pPrinterName - pointer to printer name
pdmIn - input devmode
pdmOut - output devmode
pcbNeeded - size of output buffer on input
size of output devmode on output
fMode - specifies functions to perform
Return Value:
TRUE for success and FALSE for failure
--*/
{
PCOMMONINFO pci;
DWORD dwSize, dwError;
VERBOSE(("DrvConvertDevMode: fMode = 0x%x\n", fMode));
//
// Sanity check: make sure pcbNeeded parameter is not NULL
//
if (pcbNeeded == NULL)
{
RIP(("pcbNeeded is NULL.\n"));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
switch (fMode)
{
case CDM_CONVERT:
//
// Convert input devmode to output devmode
// Note: OEM plugins are not involved here because
// they can only convert input devmode to current
// version, not between any versions.
//
if (pdmIn == NULL || pdmOut == NULL ||
*pcbNeeded < pdmOut->dmSize + pdmOut->dmDriverExtra)
{
break;
}
VSmartConvertDevmode(pdmIn, pdmOut);
*pcbNeeded = pdmOut->dmSize + pdmOut->dmDriverExtra;
return TRUE;
case CDM_CONVERT351:
//
// Convert input devmode to 3.51 version devmode
// First check if the caller provided buffer is large enough
//
dwSize = DM_SIZE320 + gDriverDMInfo.dmDriverExtra351;
if (*pcbNeeded < (LONG) dwSize || pdmOut == NULL)
{
*pcbNeeded = dwSize;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
//
// Do the conversion from input devmode to 3.51 devmode
//
pdmOut->dmSpecVersion = DM_SPECVERSION320;
pdmOut->dmSize = DM_SIZE320;
pdmOut->dmDriverVersion = gDriverDMInfo.dmDriverVersion351;
pdmOut->dmDriverExtra = gDriverDMInfo.dmDriverExtra351;
VSimpleConvertDevmode(pdmIn, pdmOut);
*pcbNeeded = dwSize;
return TRUE;
case CDM_DRIVER_DEFAULT:
//
// Get the driver default devmode.
// We need to open a handle to the printer
// and then load basic driver information.
//
dwError = ERROR_GEN_FAILURE;
pci = PLoadCommonInfo(NULL,
pPrinterName,
FLAG_OPENPRINTER_NORMAL|FLAG_OPEN_CONDITIONAL);
if (pci && BCalcTotalOEMDMSize(pci->hPrinter, pci->pOemPlugins, &dwSize))
{
dwSize += sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra;
//
// Check if the output buffer is big enough
//
if (*pcbNeeded < (LONG) dwSize || pdmOut == NULL)
dwError = ERROR_INSUFFICIENT_BUFFER;
else if (BFillCommonInfoDevmode(pci, NULL, NULL))
{
//
// Get the driver default devmode and
// copy it to the output buffer
//
CopyMemory(pdmOut, pci->pdm, dwSize);
dwError = NO_ERROR;
}
*pcbNeeded = dwSize;
}
VFreeCommonInfo(pci);
SetLastError(dwError);
return (dwError == NO_ERROR);
default:
ERR(("Invalid fMode in DrvConvertDevMode: %d\n", fMode));
break;
}
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}