661 lines
16 KiB
C
661 lines
16 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|