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.
660 lines
17 KiB
660 lines
17 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|