Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2286 lines
60 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
oemutil.c
Abstract:
Library functions to implement OEM plugin architecture
Environment:
Windows NT printer driver
Revision History:
04/17/97 -davidx-
Provide OEM plugins access to driver private settings.
01/24/97 -davidx-
Add function for loading DLLs and get entrypoint addresses.
01/21/97 -davidx-
Created it.
--*/
#define DEFINE_OEMPROC_NAMES
#include "lib.h"
#ifndef KERNEL_MODE
#include <winddiui.h>
#endif
#include <printoem.h>
#include "oemutil.h"
//
// Macros used to loop through each OEM plugin
//
#define FOREACH_OEMPLUGIN_LOOP(pOemPlugins) \
{ \
DWORD _oemCount = (pOemPlugins)->dwCount; \
POEM_PLUGIN_ENTRY pOemEntry = (pOemPlugins)->aPlugins; \
for ( ; _oemCount--; pOemEntry++) \
{
#define END_OEMPLUGIN_LOOP \
} \
}
BOOL
BExpandOemFilename(
PTSTR *ppDest,
LPCTSTR pSrc,
LPCTSTR pDir
)
/*++
Routine Description:
Expand an OEM plugin filename to a fully qualified pathname
Arguments:
ppDest - Returns a pointer to fully qualified OEM filename
pSrc - Specifies OEM filename without any directory prefix
pDir - Specifies printer driver directory
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
INT iSrcLen, iDirLen;
PTSTR pDest;
*ppDest = NULL;
if (pSrc != NULL && pDir != NULL)
{
iSrcLen = _tcslen(pSrc);
iDirLen = _tcslen(pDir);
if ((pDest = MemAlloc((iSrcLen + iDirLen + 1) * sizeof(TCHAR))) == NULL)
{
ERR(("Memory allocation failed\n"));
return FALSE;
}
CopyMemory(pDest, pDir, iDirLen * sizeof(TCHAR));
CopyMemory(pDest+iDirLen, pSrc, (iSrcLen+1) * sizeof(TCHAR));
*ppDest = pDest;
}
return TRUE;
}
POEM_PLUGINS
PGetOemPluginInfo(
HANDLE hPrinter,
LPCTSTR pctstrDriverPath,
PDRIVER_INFO_3 pDriverInfo3
)
/*++
Routine Description:
Get information about OEM plugins for a printer
Arguments:
hPrinter - Handle to a printer
pctstrDriverPath - Points to the full pathname of driver DLL
Return Value:
Pointer to OEM plugin information for the printer
NULL if there is an error
Note:
If there is no OEM plugin associated with the printer,
an OEM_PLUGINS structure is still returned but
its dwCount field will be zero.
Notice the difference between user-mode and kernel-mode implementations.
In user-mode, we're only interested in OEMConfigFileN and OEMHelpFileN.
In kernel-mode, we're only interested in OEMDriverFileN.
--*/
{
LPCTSTR driverfiles[MAX_OEM_PLUGINS];
LPCTSTR configfiles[MAX_OEM_PLUGINS];
LPCTSTR helpfiles[MAX_OEM_PLUGINS];
POEM_PLUGINS pOemPlugins;
PTSTR ptstrIniData = NULL;
PTSTR pTemp = NULL;
DWORD dwCount = 0;
//
// Retrieve the data from model-specific printer INI file
//
//
// Fixing RC1 bug #423567
//
#if 0
if (hPrinter)
ptstrIniData = PtstrGetPrinterDataMultiSZPair(hPrinter, REGVAL_INIDATA, NULL);
#endif
//
// In the following 2 cases, we need to parse the INI file:
//
// 1. hPrinter is NULL;
//
// 2. When NT5 Unidrv/PScript5 client connecting to NT4 RASDD/PScript server,
// the server printer's registry initially doesn't contain the REGVAL_INIDATA,
// so we need to parse the INI file and write it into RASDD/PScript registry.
//
if (hPrinter == NULL || ptstrIniData == NULL)
{
if (BProcessPrinterIniFile(hPrinter, pDriverInfo3, &pTemp, 0))
ptstrIniData = pTemp;
else
ptstrIniData = NULL;
}
if (ptstrIniData != NULL)
{
TCHAR atchDriverKey[20];
TCHAR atchConfigKey[20];
TCHAR atchHelpKey[20];
PTSTR ptstrDriverKeyDigit;
PTSTR ptstrConfigKeyDigit;
PTSTR ptstrHelpKeyDigit;
ZeroMemory((PVOID) driverfiles, sizeof(driverfiles));
ZeroMemory((PVOID) configfiles, sizeof(configfiles));
ZeroMemory((PVOID) helpfiles, sizeof(helpfiles));
StringCchCopyW(atchDriverKey, CCHOF(atchDriverKey), TEXT("OEMDriverFile1"));
StringCchCopyW(atchConfigKey, CCHOF(atchConfigKey), TEXT("OEMConfigFile1"));
StringCchCopyW(atchHelpKey, CCHOF(atchHelpKey), TEXT("OEMHelpFile1"));
ptstrDriverKeyDigit = &atchDriverKey[_tcslen(atchDriverKey) - 1];
ptstrConfigKeyDigit = &atchConfigKey[_tcslen(atchConfigKey) - 1];
ptstrHelpKeyDigit = &atchHelpKey[_tcslen(atchHelpKey) - 1];
while (TRUE)
{
//
// Find the files associated with the next OEM plugin.
// Stop if there are no more OEM plugins left.
//
driverfiles[dwCount] = PtstrSearchStringInMultiSZPair(ptstrIniData, atchDriverKey);
configfiles[dwCount] = PtstrSearchStringInMultiSZPair(ptstrIniData, atchConfigKey);
helpfiles[dwCount] = PtstrSearchStringInMultiSZPair(ptstrIniData, atchHelpKey);
if (!driverfiles[dwCount] && !configfiles[dwCount] && !helpfiles[dwCount])
break;
//
// Check if there are too many OEM plugins
//
if (dwCount >= MAX_OEM_PLUGINS)
{
ERR(("Exceeded max number of OEM plugins allowed: %d\n", MAX_OEM_PLUGINS));
break;
}
//
// Move on to look for the next OEM plugin
// We assume max number of plugins is less than 10
//
dwCount++;
(*ptstrDriverKeyDigit)++;
(*ptstrConfigKeyDigit)++;
(*ptstrHelpKeyDigit)++;
}
}
if ((pOemPlugins = MemAllocZ(offsetof(OEM_PLUGINS, aPlugins) +
sizeof(OEM_PLUGIN_ENTRY) * dwCount)) == NULL)
{
ERR(("Memory allocation failed\n"));
}
else if (pOemPlugins->dwCount = dwCount)
{
PTSTR ptstrDriverDir;
BOOL bResult = TRUE;
VERBOSE(("Number of OEM plugins installed: %d\n", dwCount));
dwCount = 0;
if ((ptstrDriverDir = PtstrGetDriverDirectory(pctstrDriverPath)) == NULL)
{
ERR(("Couldn't get printer driver directory\n"));
bResult = FALSE;
}
else
{
FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
#ifdef KERNEL_MODE
bResult = BExpandOemFilename(&pOemEntry->ptstrDriverFile,
driverfiles[dwCount],
ptstrDriverDir);
#else
bResult = BExpandOemFilename(&pOemEntry->ptstrConfigFile,
configfiles[dwCount],
ptstrDriverDir) &&
BExpandOemFilename(&pOemEntry->ptstrHelpFile,
helpfiles[dwCount],
ptstrDriverDir);
#endif
if (! bResult)
break;
dwCount++;
END_OEMPLUGIN_LOOP
MemFree(ptstrDriverDir);
}
if (! bResult)
{
VFreeOemPluginInfo(pOemPlugins);
pOemPlugins = NULL;
}
}
MemFree(ptstrIniData);
return pOemPlugins;
}
VOID
VFreeSinglePluginEntry(
POEM_PLUGIN_ENTRY pOemEntry
)
/*++
Routine Description:
Unload one plugin and dispose information about it
Arguments:
pOemEntry - Pointer to the single plugin entry information
Return Value:
NONE
--*/
{
if (pOemEntry->hInstance)
{
//
// Since we are calling plugin's DllInitialize(DLL_PROCESS_ATTACH)
// no matter the plugin is using COM or non-COM interface, we must
// do the same for DllInitialize(DLL_PROCESS_DETACH), so plugin will
// get balanced DllInitialize calls.
//
if (HAS_COM_INTERFACE(pOemEntry))
{
ReleaseOemInterface(pOemEntry);
#if defined(KERNEL_MODE) && defined(WINNT_40)
//
// This must be called after COM interface is released,
// because the Release() interface function still needs
// the kernel semaphore.
//
(void) BHandleOEMInitialize(pOemEntry, DLL_PROCESS_DETACH);
#endif // KERNEL_MODE && WINNT_40
//
// FreeLibrary happens in Driver_CoFreeOEMLibrary
//
#if defined(KERNEL_MODE)
if ( !(pOemEntry->dwFlags & OEMNOT_UNLOAD_PLUGIN) )
#endif
Driver_CoFreeOEMLibrary(pOemEntry->hInstance);
}
else
{
#if defined(KERNEL_MODE) && defined(WINNT_40)
(void) BHandleOEMInitialize(pOemEntry, DLL_PROCESS_DETACH);
#endif // KERNEL_MODE && WINNT_40
#if defined(KERNEL_MODE)
if ( !(pOemEntry->dwFlags & OEMNOT_UNLOAD_PLUGIN) )
#endif
FreeLibrary(pOemEntry->hInstance);
}
pOemEntry->hInstance = NULL;
}
//
// BHandleOEMInitialize needs to use the kernel mode render plugin
// DLL name, so we should free the names here.
//
MemFree(pOemEntry->ptstrDriverFile);
MemFree(pOemEntry->ptstrConfigFile);
MemFree(pOemEntry->ptstrHelpFile);
pOemEntry->ptstrDriverFile = NULL;
pOemEntry->ptstrConfigFile = NULL;
pOemEntry->ptstrHelpFile = NULL;
}
VOID
VFreeOemPluginInfo(
POEM_PLUGINS pOemPlugins
)
/*++
Routine Description:
Dispose of information about OEM plugins
Arguments:
pOemPlugins - Pointer to OEM plugin information
Return Value:
NONE
--*/
{
ASSERT(pOemPlugins != NULL);
FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
#if defined(KERNEL_MODE)
//
// If this is debug build, and if the appropriate registry flag
// (DoNotUnloadPluginDLL) is set, then the OEM plugin driver
// should not be unloaded.
// One use of this is to find out memory leaks using umdh/dhcmp.
// umdh.exe needs the plugin to be present in the memory to give a
// good stack trace.
//
DWORD dwType = 0;
DWORD ul = 0;
DWORD dwNotUnloadPluginDLL = 0;
PDEVOBJ pdevobj = (PDEVOBJ) (pOemPlugins->pdriverobj);
if( pdevobj &&
(GetPrinterData( pdevobj->hPrinter,
L"DoNotUnloadPluginDLL",
&dwType,
(LPBYTE) &dwNotUnloadPluginDLL,
sizeof( dwNotUnloadPluginDLL ),
&ul ) == ERROR_SUCCESS) &&
ul == sizeof( dwNotUnloadPluginDLL ) &&
dwNotUnloadPluginDLL )
{
pOemEntry->dwFlags |= OEMNOT_UNLOAD_PLUGIN;
}
#endif
VFreeSinglePluginEntry(pOemEntry);
END_OEMPLUGIN_LOOP
MemFree(pOemPlugins);
}
BOOL
BLoadOEMPluginModules(
POEM_PLUGINS pOemPlugins
)
/*++
Routine Description:
Load OEM plugins modules into memory
Arguments:
pOemPlugins - Points to OEM plugin info structure
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFN_OEMGetInfo pfnOEMGetInfo;
DWORD dwData, dwSize;
DWORD dwCount, dwIndex;
PTSTR ptstrDllName;
//
// Quick exit when no OEM plugin is installed
//
if (pOemPlugins->dwCount == 0)
return TRUE;
//
// Load each OEM module in turn
//
FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
//
// Load driver or config DLL depending on whether
// we're being called from kernel or user mode
//
if (ptstrDllName = CURRENT_OEM_MODULE_NAME(pOemEntry))
{
//
// Return failure if there is an error when loading the OEM module
// or if the OEM module doesn't export OEMGetInfo entrypoint
//
// Note: LoadLibraryEx is only available for UI mode and user-mode
// rendering module
//
#if defined(KERNEL_MODE) && defined(WINNT_40)
if (! (pOemEntry->hInstance = LoadLibrary(ptstrDllName)) )
{
ERR(("LoadLibrary failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
goto oemload_error;
}
//
// Notice this is called no matter plugin uses COM or non-COM interface.
//
if (!BHandleOEMInitialize(pOemEntry, DLL_PROCESS_ATTACH))
{
ERR(("BHandleOEMInitialize failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
goto oemload_error;
}
#else // !KERNEL_MODE || !WINNT_40
SetErrorMode(SEM_FAILCRITICALERRORS);
if (! (pOemEntry->hInstance = LoadLibraryEx(ptstrDllName,
NULL,
LOAD_WITH_ALTERED_SEARCH_PATH)) )
{
ERR(("LoadLibrary failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
goto oemload_error;
}
#endif // KERNEL_MODE && WINNT_40
//
// If we can get an interface from OEM plugin, then OEM is using COM interface
//
if (BGetOemInterface(pOemEntry))
{
ASSERT(pOemEntry->pIntfOem != NULL);
}
else
{
//
// Make sure to NULL the pointer to indicate no COM interface available.
//
pOemEntry->pIntfOem = NULL;
}
//
// Call OEMGetInfo to verify interface version and
// get OEM module's signature
//
if (HAS_COM_INTERFACE(pOemEntry))
{
if (!SUCCEEDED(HComOEMGetInfo(pOemEntry,
OEMGI_GETSIGNATURE,
&pOemEntry->dwSignature,
sizeof(DWORD),
&dwSize)) ||
pOemEntry->dwSignature == 0)
{
ERR(("HComOEMGetInfo failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
goto oemload_error;
}
}
else
{
if (!(pfnOEMGetInfo = GET_OEM_ENTRYPOINT(pOemEntry, OEMGetInfo)) ||
!pfnOEMGetInfo(OEMGI_GETINTERFACEVERSION, &dwData, sizeof(DWORD), &dwSize) ||
dwData != PRINTER_OEMINTF_VERSION ||
!pfnOEMGetInfo(OEMGI_GETSIGNATURE, &pOemEntry->dwSignature, sizeof(DWORD), &dwSize) ||
pOemEntry->dwSignature == 0)
{
ERR(("OEMGetInfo failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
goto oemload_error;
}
}
continue;
oemload_error:
ERR(("Failed to load OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
return FALSE;
}
END_OEMPLUGIN_LOOP
//
// Verify that no two OEM modules share the same signature
//
for (dwCount = 1; dwCount < pOemPlugins->dwCount; dwCount++)
{
POEM_PLUGIN_ENTRY pOemEntry;
pOemEntry = &pOemPlugins->aPlugins[dwCount];
if (pOemEntry->hInstance == NULL)
continue;
for (dwIndex=0; dwIndex < dwCount; dwIndex++)
{
//
// If there is a signature conflict, unload the plugin
// which appears later in the order.
//
if (pOemPlugins->aPlugins[dwIndex].dwSignature == pOemEntry->dwSignature)
{
ERR(("Duplicate signature for OEM plugins\n"));
VFreeSinglePluginEntry(pOemEntry);
pOemEntry->dwSignature = 0;
break;
}
}
}
return TRUE;
}
OEMPROC
PGetOemEntrypointAddress(
POEM_PLUGIN_ENTRY pOemEntry,
DWORD dwIndex
)
/*++
Routine Description:
Get the address for the specified OEM entrypoint
Arguments:
pOemEntry - Points to information about the OEM module
dwIndex - OEM entrypoint index
Return Value:
Address of the specified OEM entrypoint
NULL if the entrypoint is not found or if there is an error
--*/
{
ASSERT(dwIndex < MAX_OEMENTRIES);
BITSET(pOemEntry->aubProcFlags, dwIndex);
if (pOemEntry->hInstance != NULL)
{
pOemEntry->oemprocs[dwIndex] = (OEMPROC)
GetProcAddress(pOemEntry->hInstance, OEMProcNames[dwIndex]);
#if 0
if (pOemEntry->oemprocs[dwIndex] == NULL && GetLastError() != ERROR_PROC_NOT_FOUND)
ERR(("Couldn't find proc %s: %d\n", OEMProcNames[dwIndex], GetLastError()));
#endif
}
return pOemEntry->oemprocs[dwIndex];
}
POEM_PLUGIN_ENTRY
PFindOemPluginWithSignature(
POEM_PLUGINS pOemPlugins,
DWORD dwSignature
)
/*++
Routine Description:
Find the OEM plugin entry having the specified signature
Arguments:
pOemPlugins - Specifies information about all loaded OEM plugins
dwSignature - Specifies the signature in question
Return Value:
Pointer to the OEM plugin entry having the specified signature
NULL if no such entry is found
--*/
{
FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
if (pOemEntry->hInstance == NULL)
continue;
if (pOemEntry->dwSignature == dwSignature)
return pOemEntry;
END_OEMPLUGIN_LOOP
WARNING(("Cannot find OEM plugin whose signature is: 0x%x\n", dwSignature));
return NULL;
}
BOOL
BCalcTotalOEMDMSize(
HANDLE hPrinter,
POEM_PLUGINS pOemPlugins,
PDWORD pdwOemDMSize
)
/*++
Routine Description:
Calculate the total private devmode size for all OEM plugins
Arguments:
hPrinter - Handle to the current printer
pOemPlugins - Specifies information about all loaded OEM plugins
pdwOemDMSize - Return the total private size for all OEM plugins
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
DWORD dwSize;
OEMDMPARAM OemDMParam;
PFN_OEMDevMode pfnOEMDevMode;
BOOL bOemCalled;
HRESULT hr;
//
// Quick exit when no OEM plugin is installed
//
*pdwOemDMSize = dwSize = 0;
if (pOemPlugins->dwCount == 0)
return TRUE;
FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
if (pOemEntry->hInstance == NULL)
continue;
bOemCalled = FALSE;
//
// OEM private devmode size is saved in OEM_PLUGIN_ENTRY.dwOEMDMSize
// if this is the very first call, we must call into OEM plugin's
// OEMDevMode entrypoint to find out its private devmode size.
//
if (!(pOemEntry->dwFlags & OEMDEVMODE_CALLED))
{
pOemEntry->dwFlags |= OEMDEVMODE_CALLED;
//
// We reinitialize all field of OemDMParam inside
// the loop in case an ill-behaving plugin touches
// read-only fields.
//
ZeroMemory(&OemDMParam, sizeof(OemDMParam));
OemDMParam.cbSize = sizeof(OemDMParam);
OemDMParam.pdriverobj = pOemPlugins->pdriverobj;
OemDMParam.hPrinter = hPrinter;
OemDMParam.hModule = pOemEntry->hInstance;
if (HAS_COM_INTERFACE(pOemEntry))
{
hr = HComOEMDevMode(pOemEntry, OEMDM_SIZE, &OemDMParam);
if ((hr != E_NOTIMPL) && FAILED(hr))
{
ERR(("Cannot get OEM devmode size for '%ws': %d\n",
CURRENT_OEM_MODULE_NAME(pOemEntry),
GetLastError()));
return FALSE;
}
if (SUCCEEDED(hr))
bOemCalled = TRUE;
}
else
{
if (!BITTST((pOemEntry)->aubProcFlags, EP_OEMDevMode) &&
(pfnOEMDevMode = GET_OEM_ENTRYPOINT(pOemEntry, OEMDevMode)))
{
//
// Query OEM plugin to find out the size of their
// private devmode size.
//
if (! pfnOEMDevMode(OEMDM_SIZE, &OemDMParam))
{
ERR(("Cannot get OEM devmode size for '%ws': %d\n",
CURRENT_OEM_MODULE_NAME(pOemEntry),
GetLastError()));
return FALSE;
}
bOemCalled = TRUE;
}
}
if (bOemCalled)
{
//
// Make sure the OEM private devmode size is at least
// as big as OEM_DMEXTRAHEADER.
//
if (OemDMParam.cbBufSize > 0 &&
OemDMParam.cbBufSize < sizeof(OEM_DMEXTRAHEADER))
{
ERR(("OEM devmode size for '%ws' is too small: %d\n",
CURRENT_OEM_MODULE_NAME(pOemEntry),
OemDMParam.cbBufSize));
return FALSE;
}
pOemEntry->dwOEMDMSize = OemDMParam.cbBufSize;
}
}
dwSize += pOemEntry->dwOEMDMSize;
END_OEMPLUGIN_LOOP
*pdwOemDMSize = dwSize;
return TRUE;
}
BOOL
BCallOEMDevMode(
HANDLE hPrinter,
PVOID pdriverobj,
POEM_PLUGIN_ENTRY pOemEntry,
DWORD fMode,
PDEVMODE pPublicDMOut,
PDEVMODE pPublicDMIn,
POEM_DMEXTRAHEADER pOemDMOut,
POEM_DMEXTRAHEADER pOemDMIn
)
/*++
Routine Description:
Helper function to invoke OEM plugin's OEMDevMode entrypoint
Arguments:
argument-name - description of argument
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
OEMDMPARAM OemDMParam;
PFN_OEMDevMode pfnOEMDevMode;
HRESULT hr;
if (!pOemEntry->hInstance || !pOemEntry->dwOEMDMSize)
return TRUE;
//
// Call OEMDevMode to get OEM's default devmode
//
OemDMParam.cbSize = sizeof(OemDMParam);
OemDMParam.pdriverobj = pdriverobj;
OemDMParam.hPrinter = hPrinter;
OemDMParam.hModule = pOemEntry->hInstance;
OemDMParam.pPublicDMIn = pPublicDMIn;
OemDMParam.pPublicDMOut = pPublicDMOut;
OemDMParam.pOEMDMIn = pOemDMIn;
OemDMParam.pOEMDMOut = pOemDMOut;
OemDMParam.cbBufSize = pOemEntry->dwOEMDMSize;
//
// If OEM private devmode size is not 0, we should
// have OEMDevMode entrypoint address already.
//
if (HAS_COM_INTERFACE(pOemEntry))
{
hr = HComOEMDevMode(pOemEntry, fMode, &OemDMParam);
ASSERT(hr != E_NOTIMPL);
if (FAILED(hr))
{
ERR(("OEMDevMode(%d) failed for '%ws': %d\n",
fMode,
CURRENT_OEM_MODULE_NAME(pOemEntry),
GetLastError()));
return FALSE;
}
}
else
{
pfnOEMDevMode = GET_OEM_ENTRYPOINT(pOemEntry, OEMDevMode);
ASSERT(pfnOEMDevMode != NULL);
if (! pfnOEMDevMode(fMode, &OemDMParam))
{
ERR(("OEMDevMode(%d) failed for '%ws': %d\n",
fMode,
CURRENT_OEM_MODULE_NAME(pOemEntry),
GetLastError()));
return FALSE;
}
}
//
// Perform simple sanity check on the output devmode
// returned by the OEM plugin
//
if (pOemDMOut->dwSize != pOemEntry->dwOEMDMSize ||
OemDMParam.cbBufSize != pOemEntry->dwOEMDMSize ||
pOemDMOut->dwSignature != pOemEntry->dwSignature)
{
ERR(("Bad output data from OEMDevMode(%d) for '%ws'\n",
fMode,
CURRENT_OEM_MODULE_NAME(pOemEntry)));
return FALSE;
}
return TRUE;
}
BOOL
BInitOemPluginDefaultDevmode(
IN HANDLE hPrinter,
IN PDEVMODE pPublicDM,
OUT POEM_DMEXTRAHEADER pOemDM,
IN OUT POEM_PLUGINS pOemPlugins
)
/*++
Routine Description:
Initialize OEM plugin default devmodes
Arguments:
hPrinter - Handle to the current printer
pPublicDM - Points to default public devmode information
pOemDM - Points to output buffer for storing default OEM devmodes
pOemPlugins - Information about OEM plugins
Return Value:
TRUE if successful, FALSE if there is an error
Note:
After this function successfully returns, OEM_PLUGIN_ENTRY.pOEMDM field
for corresponding to each OEM plugin is updated with pointer to appropriate
private OEM devmode.
--*/
{
//
// Quick exit when no OEM plugin is installed
//
if (pOemPlugins->dwCount == 0)
return TRUE;
FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
if (pOemEntry->hInstance == NULL)
continue;
//
// Call OEM plugin to get its default private devmode
//
if (! BCallOEMDevMode(hPrinter,
pOemPlugins->pdriverobj,
pOemEntry,
OEMDM_DEFAULT,
NULL,
pPublicDM,
pOemDM,
NULL))
{
return FALSE;
}
//
// Save a pointer to current OEM plugin's private devmode
// and move on to the next OEM plugin
//
if (pOemEntry->dwOEMDMSize)
{
pOemEntry->pOEMDM = pOemDM;
pOemDM = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDM + pOemEntry->dwOEMDMSize);
}
END_OEMPLUGIN_LOOP
return TRUE;
}
BOOL
BValidateAndMergeOemPluginDevmode(
IN HANDLE hPrinter,
OUT PDEVMODE pPublicDMOut,
IN PDEVMODE pPublicDMIn,
OUT POEM_DMEXTRAHEADER pOemDMOut,
IN POEM_DMEXTRAHEADER pOemDMIn,
IN OUT POEM_PLUGINS pOemPlugins
)
/*++
Routine Description:
Validate and merge OEM plugin private devmode fields
Arguments:
hPrinter - Handle to the current printer
pPublicDMOut - Points to output public devmode
pPublicDMIn - Points to input public devmode
pOemDMOut - Points to output buffer for storing merged OEM devmodes
pOemDMIn - Points to input OEM devmodes to be merged
pOemPlugins - Information about OEM plugins
Return Value:
TRUE if successful, FALSE if there is an error
Note:
Both input and output public devmodes must be current version.
Output public devmode be already validated when this function is called.
pOemDMOut must be current version and validated as well.
pOemDMIn must be current version but may not be valid.
After this function successfully returns, OEM_PLUGIN_ENTRY.pOEMDM field
for corresponding to each OEM plugin is updated with pointer to appropriate
private OEM devmode.
--*/
{
//
// Quick exit when no OEM plugin is installed
//
if (pOemPlugins->dwCount == 0)
return TRUE;
FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
if (pOemEntry->hInstance == NULL)
continue;
//
// Call OEM plugin to validate and merge its private devmode
//
if (! BCallOEMDevMode(hPrinter,
pOemPlugins->pdriverobj,
pOemEntry,
OEMDM_MERGE,
pPublicDMOut,
pPublicDMIn,
pOemDMOut,
pOemDMIn))
{
return FALSE;
}
//
//
// Save a pointer to current OEM plugin's private devmode
// and move on to the next OEM plugin
//
if (pOemEntry->dwOEMDMSize)
{
pOemEntry->pOEMDM = pOemDMOut;
pOemDMOut = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDMOut + pOemEntry->dwOEMDMSize);
pOemDMIn = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDMIn + pOemEntry->dwOEMDMSize);
}
END_OEMPLUGIN_LOOP
return TRUE;
}
/*++
Routine Name:
bIsValidPluginDevmodes
Routine Description:
This function scans through the OEM plugin devmodes block and
verifies if every plugin devmode in that block is constructed correctly.
Arguments:
pOemDM - Points to OEM plugin devmodes block
cbOemDMSize - Size in bytes of the OEM plugin devmodes block
Return Value:
TRUE if every plugin devmode in correctly constructed.
FALSE otherwise.
Last Error:
N/A
--*/
BOOL
bIsValidPluginDevmodes(
IN POEM_DMEXTRAHEADER pOemDM,
IN LONG cbOemDMSize
)
{
OEM_DMEXTRAHEADER OemDMHeader;
BOOL bValid = FALSE;
ASSERT(pOemDM != NULL && cbOemDMSize != 0);
//
// Follow the chain of the OEM plugin devmodes, check each one's
// OEM_DMEXTRAHEADER and verify the last OEM devmode ends at the
// correct endpoint.
//
while (cbOemDMSize > 0)
{
//
// Check if the remaining OEM private devmode is big enough
//
if (cbOemDMSize < sizeof(OEM_DMEXTRAHEADER))
{
WARNING(("OEM private devmode size too small.\n"));
break;
}
//
// Copy the memory since the pointer may not be properly aligned
// if incoming devmode fields are corrupted.
//
CopyMemory(&OemDMHeader, pOemDM, sizeof(OEM_DMEXTRAHEADER));
if (OemDMHeader.dwSize < sizeof(OEM_DMEXTRAHEADER) ||
OemDMHeader.dwSize > (DWORD)cbOemDMSize)
{
WARNING(("Corrupted or truncated OEM private devmode\n"));
break;
}
//
// Move on to the next OEM plugin
//
cbOemDMSize -= OemDMHeader.dwSize;
if (cbOemDMSize == 0)
{
bValid = TRUE;
break;
}
pOemDM = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDM + OemDMHeader.dwSize);
}
return bValid;
}
BOOL
BConvertOemPluginDevmode(
IN HANDLE hPrinter,
OUT PDEVMODE pPublicDMOut,
IN PDEVMODE pPublicDMIn,
OUT POEM_DMEXTRAHEADER pOemDMOut,
IN POEM_DMEXTRAHEADER pOemDMIn,
IN LONG cbOemDMInSize,
IN POEM_PLUGINS pOemPlugins
)
/*++
Routine Description:
Convert OEM plugin default devmodes to current version
Arguments:
hPrinter - Handle to the current printer
pPublicDMOut - Points to output public devmode
pPublicDMIn - Points to input public devmode
pOemDMOut - Points to output buffer for storing merged OEM devmodes
pOemDMIn - Points to input OEM devmodes to be converted
cbOemDMInSize - Size of input buffer, in bytes
pOemPlugins - Information about OEM plugins
Return Value:
TRUE if successful, FALSE if there is an error
Note:
When this function is called, pOemDMOut must already contain
valid current version private OEM devmode information.
--*/
{
//
// Quick exit when no OEM plugin is installed or no incoming OEM devmode
//
if (pOemPlugins->dwCount == 0 || cbOemDMInSize == 0)
return TRUE;
//
// Sanity check on the incoming OEM private devmodes.
//
if (!bIsValidPluginDevmodes(pOemDMIn, cbOemDMInSize))
{
ERR(("Found wrong boundary. Incoming OEM private devmode data are ignored.\n"));
return TRUE;
}
while (cbOemDMInSize > 0)
{
POEM_PLUGIN_ENTRY pOemEntry;
OEM_DMEXTRAHEADER OemDMInHeader;
//
// Copy the memory since the pointer may not be properly aligned
// if incoming devmode fields are corrupted.
//
CopyMemory(&OemDMInHeader, pOemDMIn, sizeof(OEM_DMEXTRAHEADER));
//
// Find the OEM plugin which owns the private devmode
//
pOemEntry = PFindOemPluginWithSignature(pOemPlugins, OemDMInHeader.dwSignature);
if (pOemEntry != NULL)
{
POEM_DMEXTRAHEADER pOemDMCurrent;
DWORD dwCount;
//
// Find the OEM plugin's location in the output OEM devmode buffer
// This will always succeed because the output devmode must
// contain valid current version OEM devmodes.
//
pOemDMCurrent = pOemDMOut;
dwCount = pOemPlugins->dwCount;
while (dwCount)
{
if (pOemEntry->dwSignature == pOemDMCurrent->dwSignature)
break;
dwCount--;
pOemDMCurrent = (POEM_DMEXTRAHEADER)
((PBYTE) pOemDMCurrent + pOemDMCurrent->dwSize);
}
ASSERT(dwCount != 0);
//
// Call OEM plugin to convert its input devmode
// to its current version devmode
//
if (! BCallOEMDevMode(hPrinter,
pOemPlugins->pdriverobj,
pOemEntry,
OEMDM_CONVERT,
pPublicDMOut,
pPublicDMIn,
pOemDMCurrent,
pOemDMIn))
{
return FALSE;
}
}
else
WARNING(("No owner found for OEM devmode: 0x%x\n", pOemDMIn->dwSignature));
//
// Move on to the next OEM plugin
//
cbOemDMInSize -= OemDMInHeader.dwSize;
pOemDMIn = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDMIn + OemDMInHeader.dwSize);
}
return TRUE;
}
BOOL
BGetPrinterDataSettingForOEM(
IN PRINTERDATA *pPrinterData,
IN DWORD dwIndex,
OUT PVOID pOutput,
IN DWORD cbSize,
OUT PDWORD pcbNeeded
)
/*++
Routine Description:
Function called by OEM plugins to access driver settings in registry
Arguments:
pPrinterData - Points to the PRINTERDATA structure to be accessed
dwIndex - Predefined index specifying which field to access
pOutput - Points to output buffer
cbSize - Size of output buffer
pcbNeeded - Expected size of output buffer
Return Value:
TRUE if successful, FALSE if there is an error
--*/
#define MAPPRINTERDATAFIELD(index, field) \
{ index, offsetof(PRINTERDATA, field), sizeof(pPrinterData->field) }
{
static const struct {
DWORD dwIndex;
DWORD dwOffset;
DWORD dwSize;
} aIndexMap[] = {
MAPPRINTERDATAFIELD(OEMGDS_PRINTFLAGS, dwFlags),
MAPPRINTERDATAFIELD(OEMGDS_FREEMEM, dwFreeMem),
MAPPRINTERDATAFIELD(OEMGDS_JOBTIMEOUT, dwJobTimeout),
MAPPRINTERDATAFIELD(OEMGDS_WAITTIMEOUT, dwWaitTimeout),
MAPPRINTERDATAFIELD(OEMGDS_PROTOCOL, wProtocol),
MAPPRINTERDATAFIELD(OEMGDS_MINOUTLINE, wMinoutlinePPEM),
MAPPRINTERDATAFIELD(OEMGDS_MAXBITMAP, wMaxbitmapPPEM),
{ 0, 0, 0 }
};
INT i = 0;
while (aIndexMap[i].dwSize != 0)
{
if (aIndexMap[i].dwIndex == dwIndex)
{
*pcbNeeded = aIndexMap[i].dwSize;
if (cbSize < aIndexMap[i].dwSize || pOutput == NULL)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
CopyMemory(pOutput, (PBYTE) pPrinterData + aIndexMap[i].dwOffset, aIndexMap[i].dwSize);
return TRUE;
}
i++;
}
WARNING(("Unknown printer data index: %d\n", dwIndex));
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
BOOL
BGetGenericOptionSettingForOEM(
IN PUIINFO pUIInfo,
IN POPTSELECT pOptionsArray,
IN PCSTR pstrFeatureName,
OUT PSTR pstrOutput,
IN DWORD cbSize,
OUT PDWORD pcbNeeded,
OUT PDWORD pdwOptionsReturned
)
/*++
Routine Description:
Function called by OEM plugins to find out the currently selected
option(s) for the specified feature
Arguments:
pUIInfo - Points to UIINFO structure
pOptionsArray - Points to current option selection array
pstrFeatureName - Specifies the name of the interested feature
pOutput - Points to output buffer
cbSize - Size of output buffer
pcbNeeded - Expected size of output buffer
pdwOptionsReturned - Number of currently selected options
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFEATURE pFeature;
POPTION pOption;
PCSTR pstrOptionName;
DWORD dwFeatureIndex, dwNext, dwSize, dwCount;
ASSERT(pUIInfo && pOptionsArray && pstrFeatureName);
//
// Find the specified feature
//
pFeature = PGetNamedFeature(pUIInfo, pstrFeatureName, &dwFeatureIndex);
if (pFeature == NULL)
{
WARNING(("Unknown feature name: %s\n", pstrFeatureName));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Figure out how big the output buffer needs to be
//
dwCount = 0;
dwSize = 1;
dwNext = dwFeatureIndex;
do
{
pOption = PGetIndexedOption(pUIInfo, pFeature, pOptionsArray[dwNext].ubCurOptIndex);
if (pOption == NULL)
{
ERR(("Invalid option selection index: %d\n", dwNext));
goto first_do_next;
}
pstrOptionName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pOption->loKeywordName);
ASSERT(pstrOptionName != NULL);
dwSize += strlen(pstrOptionName) + 1;
dwCount++;
first_do_next:
dwNext = pOptionsArray[dwNext].ubNext;
} while(dwNext != NULL_OPTSELECT) ;
*pdwOptionsReturned = dwCount;
*pcbNeeded = dwSize;
//
// If the output buffer is too small, return appropriate error code
//
if (cbSize < dwSize || pstrOutput == NULL)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
//
// Copy the selected option names
//
dwNext = dwFeatureIndex;
do
{
pOption = PGetIndexedOption(pUIInfo, pFeature, pOptionsArray[dwNext].ubCurOptIndex);
if (pOption == NULL)
{
ERR(("Invalid option selection index: %d\n", dwNext));
goto second_do_next;
}
pstrOptionName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pOption->loKeywordName);
dwSize = strlen(pstrOptionName) + 1;
CopyMemory(pstrOutput, pstrOptionName, dwSize);
pstrOutput += dwSize;
second_do_next:
dwNext = pOptionsArray[dwNext].ubNext;
} while(dwNext != NULL_OPTSELECT) ;
//
// Don't forget the extra NUL character at the end
//
*pstrOutput = NUL;
return TRUE;
}
VOID
VPatchDevmodeSizeFields(
PDEVMODE pdm,
DWORD dwDriverDMSize,
DWORD dwOemDMSize
)
/*++
Routine Description:
Patch various size fields in the devmode structure
Arguments:
pdm - Points to devmode structure to be patched
dwDriverDMSize - Size of driver private devmode
dwOemDMSize - Size of OEM plugin private devmodes
Return Value:
NONE
--*/
{
pdm->dmDriverExtra = (WORD) (dwDriverDMSize + dwOemDMSize);
if (gdwDriverDMSignature == PSDEVMODE_SIGNATURE)
{
PPSDRVEXTRA pPsExtra = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdm);
pPsExtra->wSize = (WORD) dwDriverDMSize;
pPsExtra->wOEMExtra = (WORD) dwOemDMSize;
}
else
{
PUNIDRVEXTRA pUniExtra = (PUNIDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdm);
pUniExtra->wSize = (WORD) dwDriverDMSize;
pUniExtra->wOEMExtra = (WORD) dwOemDMSize;
}
}
PDEVMODE
PGetDefaultDevmodeWithOemPlugins(
IN LPCTSTR ptstrPrinterName,
IN PUIINFO pUIInfo,
IN PRAWBINARYDATA pRawData,
IN BOOL bMetric,
IN OUT POEM_PLUGINS pOemPlugins,
IN HANDLE hPrinter
)
/*++
Routine Description:
Allocate memory and initialize it with default devmode information
This include public devmode, driver private devmode, as well as
private devmode for any OEM plugins.
Arguments:
ptstrPrinterName - Name of the current printer
pUIInfo - Points to a UIINFO structure
pRawData - Points to raw binary printer description data
bMetric - Whether the system is in metric country
pOemPlugins - Points to information about OEM plugins
hPrinter - Handle to the current printer
Return Value:
Pointer to a devmode structure (including driver private and
OEM plugin private devmodes) initialized to default settings;
NULL if there is an error
--*/
{
PDEVMODE pdm;
DWORD dwOemDMSize, dwSystemDMSize;
//
// Figure out the total devmode size and allocate memory:
// public fields
// driver private fields
// OEM plugin private fields, if any
//
dwSystemDMSize = sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra;
if (! BCalcTotalOEMDMSize(hPrinter, pOemPlugins, &dwOemDMSize) ||
! (pdm = MemAllocZ(dwOemDMSize + dwSystemDMSize)))
{
return NULL;
}
//
// Call driver-specific function to initialize public and driver private fields
// Call OEM plugins to initialize their default devmode fields
//
if (! BInitDriverDefaultDevmode(pdm, ptstrPrinterName, pUIInfo, pRawData, bMetric) ||
! BInitOemPluginDefaultDevmode(
hPrinter,
pdm,
(POEM_DMEXTRAHEADER) ((PBYTE) pdm + dwSystemDMSize),
pOemPlugins))
{
MemFree(pdm);
return NULL;
}
//
// Patch up various private devmode size fields
//
VPatchDevmodeSizeFields(pdm, gDriverDMInfo.dmDriverExtra, dwOemDMSize);
return pdm;
}
PDEVMODE
PConvertToCurrentVersionDevmodeWithOemPlugins(
IN HANDLE hPrinter,
IN PRAWBINARYDATA pRawData,
IN PDEVMODE pdmInput,
IN PDEVMODE pdmDefault,
IN POEM_PLUGINS pOemPlugins,
OUT PDWORD pdwOemDMSize
)
/*++
Routine Description:
Convert input devmode to current version devmode.
Memory for the converted devmode is allocated by this function.
Arguments:
hPrinter - Handle to the current printer
pRawData - Points to raw binary printer description data
pdmInput - Pointer to the input devmode to be converted
pdmDefault - Points to a valid current version devmode
pOemPlugins - Information about OEM plugins
pdwOemDMSize - Returns the total size of all OEM plugin devmodes
Return Value:
Pointer to the converted devmode, NULL if there is an error
Note:
Core private devmode portion of returned devmode contains:
1) if pdmInput is from unknown driver (including Rasdd):
core private devmode portion from pdmDefault
2) if pdmInput is from our NT4 PScript/Win2K/XP/Longhorn+ drivers:
fixed-size core private devmode of pdmInput
--*/
{
DWORD dwOemDMSize;
WORD wCoreFixSize, wOEMExtra;
PDEVMODE pdm;
PVOID pDrvExtraIn, pOemDMOut, pOemDMIn;
BOOL bMSdm500In = FALSE, bMSdmPS4In = FALSE;
ASSERT(pdmInput != NULL);
//
// Allocate memory to hold converted devmode
//
if (! BCalcTotalOEMDMSize(hPrinter, pOemPlugins, &dwOemDMSize) ||
! (pdm = MemAllocZ(dwOemDMSize + gDriverDMInfo.dmDriverExtra + sizeof(DEVMODE))))
{
return NULL;
}
//
// Copy public devmode fields
//
CopyMemory(pdm, pdmInput, min(sizeof(DEVMODE), pdmInput->dmSize));
pdm->dmSpecVersion = DM_SPECVERSION;
pdm->dmSize = sizeof(DEVMODE);
//
// Copy driver private devmode fields
//
pDrvExtraIn = GET_DRIVER_PRIVATE_DEVMODE(pdmInput);
wCoreFixSize = pdmInput->dmDriverExtra;
wOEMExtra = 0;
if (pdmInput->dmDriverVersion >= gDriverDMInfo.dmDriverVersion500 &&
wCoreFixSize >= gDriverDMInfo.dmDriverExtra500)
{
//
// Win2K/XP/Longhorn+ drivers must be allowed to enter this if-block
//
// (Note that in UNIDRVEXTRA500 we didn't have the last "dwEndingPad"
// field, since that field is only added in XP. And for PSDRIVER_VERSION_500
// we are using the Win2K's number 0x501.)
//
WORD wSize = wCoreFixSize;
if (gdwDriverDMSignature == PSDEVMODE_SIGNATURE)
{
if (((PPSDRVEXTRA) pDrvExtraIn)->dwSignature == PSDEVMODE_SIGNATURE)
{
wSize = ((PPSDRVEXTRA) pDrvExtraIn)->wSize;
wOEMExtra = ((PPSDRVEXTRA) pDrvExtraIn)->wOEMExtra;
if ((wSize >= gDriverDMInfo.dmDriverExtra500) &&
((wSize + wOEMExtra) <= pdmInput->dmDriverExtra))
{
//
// pdmInput is from our Win2K/XP/Longhorn+ PScript driver
//
bMSdm500In = TRUE;
}
}
}
else
{
if (((PUNIDRVEXTRA) pDrvExtraIn)->dwSignature == UNIDEVMODE_SIGNATURE)
{
wSize = ((PUNIDRVEXTRA) pDrvExtraIn)->wSize;
wOEMExtra = ((PUNIDRVEXTRA) pDrvExtraIn)->wOEMExtra;
if ((wSize >= gDriverDMInfo.dmDriverExtra500) &&
((wSize + wOEMExtra) <= pdmInput->dmDriverExtra))
{
//
// pdmInput is from our Win2K/XP/Longhorn+ Unidrv driver
//
bMSdm500In = TRUE;
}
}
}
if (bMSdm500In && (wCoreFixSize > wSize))
wCoreFixSize = wSize;
}
else
{
if (gdwDriverDMSignature == PSDEVMODE_SIGNATURE)
{
if (pdmInput->dmDriverVersion == PSDRIVER_VERSION_400 &&
wCoreFixSize == sizeof(PSDRVEXTRA400) &&
(((PSDRVEXTRA400 *) pDrvExtraIn)->dwSignature == PSDEVMODE_SIGNATURE))
{
//
// pdmInput is from our NT4 PScript driver
//
bMSdmPS4In = TRUE;
}
}
}
//
// Possible sources for pdmInput and their outcome at this point:
//
// 1. unknown driver (including NT4 Rasdd)
// bMSdm500In = FALSE, bMSdmPS4in = FALSE,
// wCoreFixSize = pdmInput->dmDriverExtra, wOEMExtra = 0
//
// 2. NT4 PScript driver
// bMSdm500In = FALSE, bMSdmPS4in = TRUE,
// wCoreFixSize = pdmInput->dmDriverExtra, wOEMExtra = 0
//
// 3. Win2K/XP driver without plugin
// bMSdm500In = TRUE, bMSdmPS4in = FALSE,
// wCoreFixSize = pdmInput->dmDriverExtra, wOEMExtra = 0
//
// 4. Win2K/XP driver with plugin
// bMSdm500In = TRUE, bMSdmPS4in = FALSE,
// wCoreFixSize = pdmInPriv->wSize < pdmInput->dmDriverExtra,
// wOEMExtra = pdmInPriv->wOEMExtra > 0
//
if (bMSdm500In || bMSdmPS4In)
{
CopyMemory(GET_DRIVER_PRIVATE_DEVMODE(pdm),
pDrvExtraIn,
min(gDriverDMInfo.dmDriverExtra, wCoreFixSize));
}
else
{
//
// pdmInput is from unknown driver, so copy our default private devmode.
// We don't want to copy unknown private devmode and then change all the
// size/version fields to have our current driver's values.
//
WARNING(("Input devmode is unknown, so ignore its private portion.\n"));
CopyMemory(GET_DRIVER_PRIVATE_DEVMODE(pdm),
GET_DRIVER_PRIVATE_DEVMODE(pdmDefault),
gDriverDMInfo.dmDriverExtra);
}
//
// Validate option array setting in the input devmode and correct
// any invalid option selections. This is needed since our future
// code assumes that the option array always have valid settings.
//
if (bMSdm500In)
{
PVOID pDrvExtraOut;
POPTSELECT pOptions;
//
// We are dealing with input devmode of Win2K/XP/Longhorn+ inbox drivers
//
pDrvExtraOut = GET_DRIVER_PRIVATE_DEVMODE(pdm);
if (gdwDriverDMSignature == PSDEVMODE_SIGNATURE)
{
pOptions = ((PPSDRVEXTRA) pDrvExtraOut)->aOptions;
}
else
{
pOptions = ((PUNIDRVEXTRA) pDrvExtraOut)->aOptions;
}
//
// validate input devmode option array and correct any invalid selections
//
ValidateDocOptions(pRawData,
pOptions,
MAX_PRINTER_OPTIONS);
}
pdm->dmDriverVersion = gDriverDMInfo.dmDriverVersion;
//
// CopyMemory above overwrote size fields in private devmode, need to restore them.
//
VPatchDevmodeSizeFields(pdm, gDriverDMInfo.dmDriverExtra, dwOemDMSize);
if (dwOemDMSize)
{
//
// Convert OEM plugin private devmodes.
// Start out with valid default settings.
//
pOemDMOut = (PBYTE) pdm + (sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra);
CopyMemory(pOemDMOut,
(PBYTE) pdmDefault + (sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra),
dwOemDMSize);
//
// Plugins are only supported by our Win2K and above drivers.
//
if (bMSdm500In && (wOEMExtra > 0) && (pdmInput->dmDriverExtra > wCoreFixSize))
{
pOemDMIn = (PBYTE) pdmInput + (pdmInput->dmSize + wCoreFixSize);
//
// We used to use "pdmInput->dmDriverExtra - wCoreFixSize" instead of "wOEMExtra"
// in this call, but that is under the assumption that everything after the core
// fixed fields are plugin devmodes. That assumption may not be true in Longhorn.
//
if (! BConvertOemPluginDevmode(
hPrinter,
pdm,
pdmInput,
pOemDMOut,
pOemDMIn,
(LONG)wOEMExtra,
pOemPlugins))
{
MemFree(pdm);
return NULL;
}
}
}
*pdwOemDMSize = dwOemDMSize;
return pdm;
}
BOOL
BValidateAndMergeDevmodeWithOemPlugins(
IN OUT PDEVMODE pdmOutput,
IN PUIINFO pUIInfo,
IN PRAWBINARYDATA pRawData,
IN PDEVMODE pdmInput,
IN OUT POEM_PLUGINS pOemPlugins,
IN HANDLE hPrinter
)
/*++
Routine Description:
Valicate input devmode and merge it into the output devmode.
This include public devmode, driver private devmode, as well as
private devmode for any OEM plugins.
Arguments:
pdmOutput - Points to the output devmode
pUIInfo - Points to a UIINFO structure
pRawData - Points to raw binary printer description data
pdmInput - Points to the input devmode
pOemPlugins - Points to information about OEM plugins
hPrinter - Handle to the current printer
Return Value:
TRUE if successful, FALSE otherwise
Note:
The output devmode must be a valid current version devmode
when this function is called.
--*/
{
PDEVMODE pdmConverted;
DWORD dwOemDMSize;
BOOL bResult;
if (pdmInput == NULL)
return TRUE;
//
// Otherwise, convert the input devmode to current version first
//
pdmConverted = PConvertToCurrentVersionDevmodeWithOemPlugins(
hPrinter,
pRawData,
pdmInput,
pdmOutput,
pOemPlugins,
&dwOemDMSize);
if ((pdmInput = pdmConverted) == NULL)
return FALSE;
//
// Validate and merge public and driver private devmode fields
//
bResult = BMergeDriverDevmode(pdmOutput, pUIInfo, pRawData, pdmInput);
//
// Validate and merge OEM plugin private devmode fields
//
if (bResult && dwOemDMSize)
{
DWORD dwSystemDMSize = sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra;
bResult = BValidateAndMergeOemPluginDevmode(
hPrinter,
pdmOutput,
pdmInput,
(POEM_DMEXTRAHEADER) ((PBYTE) pdmOutput + dwSystemDMSize),
(POEM_DMEXTRAHEADER) ((PBYTE) pdmInput + dwSystemDMSize),
pOemPlugins);
}
MemFree(pdmConverted);
return bResult;
}
#if defined(KERNEL_MODE) && defined(WINNT_40)
BOOL
BOEMPluginFirstLoad(
IN PTSTR ptstrDriverFile,
IN OUT POEM_PLUGIN_REFCOUNT *ppOEMPluginRefCount
)
/*++
Routine Description:
Maintains ref count for the render plugin DLL and determines if it's
loaded for the first time.
Arguments:
ptstrDriverFile - OEM render plugin DLL name with fully qualified path
ppOEMPluginRefCount - pointer to the pointer of OEM render plugin ref count link list
Return Value:
TRUE: the render plugin DLL is loaded for the first time
FALSE: otherwise
--*/
{
POEM_PLUGIN_REFCOUNT pRefCount;
PTSTR ptstrPluginDllName;
INT iDllNameLen;
ASSERT(ptstrDriverFile && ppOEMPluginRefCount);
//
// Get the plugin DLL name without any path prefix
//
if ((ptstrPluginDllName = _tcsrchr(ptstrDriverFile, TEXT(PATH_SEPARATOR))) == NULL)
{
WARNING(("Plugin DLL path is not fully qualified: %ws\n", ptstrDriverFile));
ptstrPluginDllName = ptstrDriverFile;
}
else
{
ptstrPluginDllName++; // skip the last '\'
}
iDllNameLen = _tcslen(ptstrPluginDllName);
pRefCount = *ppOEMPluginRefCount;
//
// Search to see if the plugin DLL name is already in the ref count link list
//
while (pRefCount)
{
if (_tcsicmp(pRefCount->ptstrDriverFile, ptstrPluginDllName) == EQUAL_STRING)
{
break;
}
pRefCount = pRefCount->pNext;
}
if (pRefCount == NULL)
{
//
// A new plugin DLL is loaded. Add it to the ref count link list.
//
if ((pRefCount = MemAllocZ(sizeof(OEM_PLUGIN_REFCOUNT) + (iDllNameLen + 1)*sizeof(TCHAR))) == NULL)
{
ERR(("Memory allocation failed\n"));
return FALSE;
}
pRefCount->ptstrDriverFile = (PTSTR)((PBYTE)pRefCount + sizeof(OEM_PLUGIN_REFCOUNT));
pRefCount->dwRefCount = 1;
CopyMemory(pRefCount->ptstrDriverFile, ptstrPluginDllName, iDllNameLen * sizeof(TCHAR));
pRefCount->pNext = *ppOEMPluginRefCount;
*ppOEMPluginRefCount = pRefCount;
return TRUE;
}
else
{
//
// The plugin DLL name is already in the ref count link list, so just increase its ref count.
//
pRefCount->dwRefCount++;
return FALSE;
}
}
BOOL
BOEMPluginLastUnload(
IN PTSTR ptstrDriverFile,
IN OUT POEM_PLUGIN_REFCOUNT *ppOEMPluginRefCount
)
/*++
Routine Description:
Maintains ref count for the render plugin DLL and determines if it's
unloaded by the last client.
Arguments:
ptstrDriverFile - OEM render plugin DLL name with fully qualified path
ppOEMPluginRefCount - pointer to the pointer of OEM render plugin ref count link list
Return Value:
TRUE: the render plugin DLL is unloaded by the last client
FALSE: otherwise
--*/
{
POEM_PLUGIN_REFCOUNT pRefCountPrev, pRefCount;
PTSTR ptstrPluginDllName;
ASSERT(ptstrDriverFile && ppOEMPluginRefCount);
//
// Get the plugin DLL name without any path prefix
//
if ((ptstrPluginDllName = _tcsrchr(ptstrDriverFile, TEXT(PATH_SEPARATOR))) == NULL)
{
WARNING(("Plugin DLL path is not fully qualified: %ws\n", ptstrDriverFile));
ptstrPluginDllName = ptstrDriverFile;
}
else
{
ptstrPluginDllName++; // skip the last '\'
}
pRefCountPrev = NULL;
pRefCount = *ppOEMPluginRefCount;
//
// Search to locate the plugin DLL entry in the ref count link list
//
while (pRefCount)
{
if (_tcsicmp(pRefCount->ptstrDriverFile, ptstrPluginDllName) == EQUAL_STRING)
{
break;
}
pRefCountPrev = pRefCount;
pRefCount = pRefCount->pNext;
}
if (pRefCount == NULL)
{
RIP(("Plugin DLL name is not in the ref count list: %ws\n", ptstrPluginDllName));
return FALSE;
}
if (--(pRefCount->dwRefCount) == 0)
{
//
// If the ref count decreases to 0, we need to remove the plugin DLL from the ref
// count link list.
//
if (pRefCountPrev == NULL)
{
*ppOEMPluginRefCount = pRefCount->pNext;
}
else
{
pRefCountPrev->pNext = pRefCount->pNext;
}
MemFree(pRefCount);
return TRUE;
}
return FALSE;
}
VOID
VFreePluginRefCountList(
IN OUT POEM_PLUGIN_REFCOUNT *ppOEMPluginRefCount
)
/*++
Routine Description:
Free memory allocated in the ref count link list, and remove all the nodes in the list.
Finally the link list will be reset to empty.
Arguments:
ppOEMPluginRefCount - pointer to the pointer of OEM render plugin ref count link list
Return Value:
None
--*/
{
POEM_PLUGIN_REFCOUNT pRefCountRemove, pRefCount;
pRefCount = *ppOEMPluginRefCount;
while (pRefCount)
{
pRefCountRemove = pRefCount;
pRefCount = pRefCount->pNext;
MemFree(pRefCountRemove);
}
*ppOEMPluginRefCount = NULL;
}
#endif // KERNEL_MODE && WINNT_40