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.
 
 
 
 
 
 

954 lines
23 KiB

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
oemkm.c
Abstract:
Kernel mode support for OEM plugins
Environment:
Windows NT Unidrv driver
Revision History:
04/01/97 -zhanw-
Adapted from Pscript source
--*/
#include "unidrv.h"
#ifdef WINNT_40
//
// The global link list of ref counts for currently loaded OEM render plugin DLLs
//
POEM_PLUGIN_REFCOUNT gpOEMPluginRefCount;
static const CHAR szDllInitialize[] = "DllInitialize";
#endif // WINNT_40
//
// Unidrv specific OEM entrypoints
//
// NOTE: Please keep this in sync with indices defined in printer5\inc\oemutil.h!!!
//
static CONST PSTR OEMUnidrvProcNames[MAX_UNIDRV_ONLY_HOOKS] = {
"OEMCommandCallback",
"OEMImageProcessing",
"OEMFilterGraphics",
"OEMCompression",
"OEMHalftonePattern",
"OEMMemoryUsage",
"OEMDownloadFontHeader",
"OEMDownloadCharGlyph",
"OEMTTDownloadMethod",
"OEMOutputCharStr",
"OEMSendFontCmd",
"OEMTTYGetInfo",
"OEMTextOutAsBitmap",
"OEMWritePrinter",
};
static CONST PSTR COMUnidrvProcNames[MAX_UNIDRV_ONLY_HOOKS] = {
"CommandCallback",
"ImageProcessing",
"FilterGraphics",
"Compression",
"HalftonePattern",
"MemoryUsage",
"DownloadFontHeader",
"DownloadCharGlyph",
"TTDownloadMethod",
"OutputCharStr",
"SendFontCmd",
"TTYGetInfo",
"TextOutAsBitmap",
"WritePrinter",
};
//
// OEM plugin helper function table
//
static const DRVPROCS OEMHelperFuncs = {
(PFN_DrvWriteSpoolBuf) WriteSpoolBuf,
(PFN_DrvXMoveTo) XMoveTo,
(PFN_DrvYMoveTo) YMoveTo,
(PFN_DrvGetDriverSetting) BGetDriverSettingForOEM,
(PFN_DrvGetStandardVariable) BGetStandardVariable,
(PFN_DrvUnidriverTextOut) FMTextOut,
(PFN_DrvWriteAbortBuf) WriteAbortBuf,
};
INT
IMapDDIIndexToOEMIndex(
ULONG ulDdiIndex
)
/*++
Routine Description:
Maps DDI entrypoint index to OEM entrypoint index
Arguments:
ulDdiIndex - DDI entrypoint index
Return Value:
OEM entrypoint index corresponding to the specified DDI entrypoint index
-1 if the specified DDI entrypoint cannot be hooked out by OEM plugins
--*/
{
static const struct {
ULONG ulDdiIndex;
INT iOemIndex;
}
OemToDdiMapping[] =
{
INDEX_DrvRealizeBrush, EP_OEMRealizeBrush,
INDEX_DrvDitherColor, EP_OEMDitherColor,
INDEX_DrvCopyBits, EP_OEMCopyBits,
INDEX_DrvBitBlt, EP_OEMBitBlt,
INDEX_DrvStretchBlt, EP_OEMStretchBlt,
#ifndef WINNT_40
INDEX_DrvStretchBltROP, EP_OEMStretchBltROP,
INDEX_DrvPlgBlt, EP_OEMPlgBlt,
INDEX_DrvTransparentBlt, EP_OEMTransparentBlt,
INDEX_DrvAlphaBlend, EP_OEMAlphaBlend,
INDEX_DrvGradientFill, EP_OEMGradientFill,
#endif
INDEX_DrvTextOut, EP_OEMTextOut,
INDEX_DrvStrokePath, EP_OEMStrokePath,
INDEX_DrvFillPath, EP_OEMFillPath,
INDEX_DrvStrokeAndFillPath, EP_OEMStrokeAndFillPath,
INDEX_DrvPaint, EP_OEMPaint,
INDEX_DrvLineTo, EP_OEMLineTo,
INDEX_DrvStartPage, EP_OEMStartPage,
INDEX_DrvSendPage, EP_OEMSendPage,
INDEX_DrvEscape, EP_OEMEscape,
INDEX_DrvStartDoc, EP_OEMStartDoc,
INDEX_DrvEndDoc, EP_OEMEndDoc,
INDEX_DrvNextBand, EP_OEMNextBand,
INDEX_DrvStartBanding, EP_OEMStartBanding,
INDEX_DrvQueryFont, EP_OEMQueryFont,
INDEX_DrvQueryFontTree, EP_OEMQueryFontTree,
INDEX_DrvQueryFontData, EP_OEMQueryFontData,
INDEX_DrvQueryAdvanceWidths, EP_OEMQueryAdvanceWidths,
INDEX_DrvFontManagement, EP_OEMFontManagement,
INDEX_DrvGetGlyphMode, EP_OEMGetGlyphMode,
};
INT iIndex;
INT iLimit = sizeof(OemToDdiMapping) / (sizeof(INT) * 2);
for (iIndex=0; iIndex < iLimit; iIndex++)
{
if (OemToDdiMapping[iIndex].ulDdiIndex == ulDdiIndex)
return OemToDdiMapping[iIndex].iOemIndex;
}
return -1;
}
BOOL
BLoadAndInitOemPlugins(
PDEV *pPDev
)
/*++
Routine Description:
Get information about OEM plugins associated with the current device
Load them into memory and call OEMEnableDriver for each of them
Arguments:
pPDev - Points to our device data structure
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFN_OEMEnableDriver pfnOEMEnableDriver;
DRVENABLEDATA ded;
DWORD dwCount;
INT iIndex;
PDRVFN pdrvfn;
OEMPROC oemproc;
//
// Load OEM plugins into memory
//
pPDev->devobj.pDrvProcs = (PDRVPROCS) &OEMHelperFuncs;
if (! (pPDev->pOemPlugins = PGetOemPluginInfo(pPDev->devobj.hPrinter,
pPDev->pDriverInfo3->pDriverPath,
pPDev->pDriverInfo3)) ||
! BLoadOEMPluginModules(pPDev->pOemPlugins))
{
return FALSE;
}
//
// Init pdriverobj to point to devobj for OEM to access private setting
//
pPDev->pOemPlugins->pdriverobj = &pPDev->devobj;
//
// If there is no OEM plugin, return success
//
if (pPDev->pOemPlugins->dwCount == 0)
return TRUE;
//
// Call OEM plugin's OEMEnableDriver entrypoint
// and find out if any of them has hook out DDI entrypoints
//
pPDev->pOemHookInfo = MemAllocZ(sizeof(OEM_HOOK_INFO) * MAX_OEMHOOKS);
if (pPDev->pOemHookInfo == NULL)
return FALSE;
START_OEMENTRYPOINT_LOOP(pPDev)
// this macro defined in oemkm.h in conjunction with its partner END_OEMENTRYPOINT_LOOP,
// acts like a for() loop initializing and incrementing pOemEntry each pass through the
// loop.
ZeroMemory(&ded, sizeof(ded));
//
// COM Plug-in case
//
if (pOemEntry->pIntfOem != NULL)
{
HRESULT hr;
hr = HComOEMEnableDriver(pOemEntry,
PRINTER_OEMINTF_VERSION,
sizeof(ded),
&ded);
if (hr == E_NOTIMPL)
goto UNIDRV_SPECIFIC;
if (FAILED(hr))
{
ERR(("OEMEnableDriver failed for '%ws': %d\n",
pOemEntry->ptstrDriverFile,
GetLastError()));
break;
}
}
//
// Non-COM Plug-in case
//
else
{
if (!(pfnOEMEnableDriver = GET_OEM_ENTRYPOINT(pOemEntry, OEMEnableDriver)))
goto UNIDRV_SPECIFIC;
//
// Call OEM plugin's entrypoint
//
if (! pfnOEMEnableDriver(PRINTER_OEMINTF_VERSION, sizeof(ded), &ded))
{
ERR(("OEMEnableDriver failed for '%ws': %d\n",
pOemEntry->ptstrDriverFile,
GetLastError()));
break;
}
//
// Verify the driver version (do this only if not COM)
//
if (ded.iDriverVersion != PRINTER_OEMINTF_VERSION)
{
ERR(("Invalid driver version for '%ws': 0x%x\n",
pOemEntry->ptstrDriverFile,
ded.iDriverVersion));
break;
}
}
pOemEntry->dwFlags |= OEMENABLEDRIVER_CALLED;
//
// Check if OEM plugin has hooked out any DDI entrypoints
//
for (dwCount=ded.c, pdrvfn=ded.pdrvfn; dwCount-- > 0; pdrvfn++)
{
if ((iIndex = IMapDDIIndexToOEMIndex(pdrvfn->iFunc)) >= 0)
{
if (pPDev->pOemHookInfo[iIndex].pfnHook != NULL)
{
WARNING(("Multiple hooks for entrypoint: %d\n"
" %ws\n"
" %ws\n",
iIndex,
pOemEntry->ptstrDriverFile,
pPDev->pOemHookInfo[iIndex].pOemEntry->ptstrDriverFile));
}
else
{
pPDev->pOemHookInfo[iIndex].pfnHook = (OEMPROC) pdrvfn->pfn;
pPDev->pOemHookInfo[iIndex].pOemEntry = pOemEntry;
}
}
}
//
// check if OEM plugin has any Unidrv-specific callbacks exported
//
UNIDRV_SPECIFIC:
for (dwCount = 0; dwCount < MAX_UNIDRV_ONLY_HOOKS; dwCount++)
{
oemproc = NULL;
if(pOemEntry->pIntfOem) // is this a COM component, do special processing
{
if(S_OK == HComGetImplementedMethod(pOemEntry, COMUnidrvProcNames[dwCount]) )
oemproc = (OEMPROC)pOemEntry;
// note oemproc/pfnHook only used as a BOOLEAN in COM path code.
// do not use pfnHook to call a COM function! we will use
// ganeshp's wrapper functions (declared in unidrv2\inc\oemkm.h) to do this.
}
else if (pOemEntry->hInstance != NULL)
oemproc = (OEMPROC) GetProcAddress(pOemEntry->hInstance,
OEMUnidrvProcNames[dwCount]) ;
if(oemproc)
{
//
// check if another OEM has already hooked out this function.
// If so, ignore this one.
//
iIndex = dwCount + EP_UNIDRV_ONLY_FIRST;
if (pPDev->pOemHookInfo[iIndex].pfnHook != NULL)
{
WARNING(("Multiple hooks for entrypoint: %d\n"
" %ws\n"
" %ws\n",
iIndex,
pOemEntry->ptstrDriverFile,
pPDev->pOemHookInfo[iIndex].pOemEntry->ptstrDriverFile));
}
else
{
DWORD dwSize;
HRESULT hr;
pPDev->pOemHookInfo[iIndex].pfnHook = oemproc;
pPDev->pOemHookInfo[iIndex].pOemEntry = pOemEntry;
//
// Set WritePrinter flag (OEMWRITEPRINTER_HOOKED).
// Plug-in DLL needs to return S_OK with pBuff = NULL, size = 0,
// and pdevobj = NULL.
//
if (iIndex == EP_OEMWritePrinter)
{
hr = HComWritePrinter(pOemEntry,
NULL,
NULL,
0,
&dwSize);
if (hr == S_OK)
{
//
// Set WritePrinter hook flag in plug-in info.
//
pOemEntry->dwFlags |= OEMWRITEPRINTER_HOOKED;
//
// Set WritePrinter hook flag in UNIDRV PDEV.
//
pPDev->fMode2 |= PF2_WRITE_PRINTER_HOOKED;
}
}
}
}
}
END_OEMENTRYPOINT_LOOP
//
// cache callback function ptrs
//
pPDev->pfnOemCmdCallback =
(PFN_OEMCommandCallback)pPDev->pOemHookInfo[EP_OEMCommandCallback].pfnHook;
return TRUE;
}
VOID
VUnloadOemPlugins(
PDEV *pPDev
)
/*++
Routine Description:
Unload OEM plugins and free all relevant resources
Arguments:
pPDev - Points to our device data structure
Return Value:
NONE
--*/
{
PFN_OEMDisableDriver pfnOEMDisableDriver;
PFN_OEMDisablePDEV pfnOEMDisablePDEV;
if (pPDev->pOemPlugins == NULL)
return;
//
// Call OEMDisablePDEV for all OEM plugins, if necessary
//
START_OEMENTRYPOINT_LOOP(pPDev)
if (pOemEntry->dwFlags & OEMENABLEPDEV_CALLED)
{
if (pOemEntry->pIntfOem != NULL)
{
(VOID)HComOEMDisablePDEV(pOemEntry, (PDEVOBJ)pPDev);
}
else
{
if (pfnOEMDisablePDEV = GET_OEM_ENTRYPOINT(pOemEntry, OEMDisablePDEV))
{
pfnOEMDisablePDEV((PDEVOBJ) pPDev);
}
}
}
END_OEMENTRYPOINT_LOOP
//
// Call OEMDisableDriver for all OEM plugins, if necessary
//
START_OEMENTRYPOINT_LOOP(pPDev)
if (pOemEntry->dwFlags & OEMENABLEDRIVER_CALLED)
{
if (pOemEntry->pIntfOem != NULL)
{
(VOID)HComOEMDisableDriver(pOemEntry);
}
else
{
if ((pfnOEMDisableDriver = GET_OEM_ENTRYPOINT(pOemEntry, OEMDisableDriver)))
{
pfnOEMDisableDriver();
}
}
}
END_OEMENTRYPOINT_LOOP
MemFree(pPDev->pOemHookInfo);
pPDev->pOemHookInfo = NULL;
VFreeOemPluginInfo(pPDev->pOemPlugins);
pPDev->pOemPlugins = NULL;
}
BOOL
BGetDriverSettingForOEM(
PDEV *pPDev,
PCSTR pFeatureKeyword,
PVOID pOutput,
DWORD cbSize,
PDWORD pcbNeeded,
PDWORD pdwOptionsReturned
)
/*++
Routine Description:
Provide OEM plugins access to driver private settings
Arguments:
pDev - Points to our device data structure
pFeatureKeyword - Specifies the keyword the caller is interested in
pOutput - Points to output buffer
cbSize - Size of output buffer
pcbNeeded - Returns the expected size of output buffer
pdwOptionsReturned - Returns the number of options selected
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
ULONG_PTR dwIndex;
BOOL bResult;
ASSERT_VALID_PDEV(pPDev);
//
// This is not very portable: If the pointer value for pFeatureKeyword
// is less than 0x10000, we assume that the pointer value actually
// specifies a predefined index.
//
// ASSERT(sizeof(pFeatureKeyword) == sizeof(DWORD)); changed for sundown
dwIndex = (ULONG_PTR) pFeatureKeyword;
if (dwIndex >= OEMGDS_MIN_DOCSTICKY && dwIndex < OEMGDS_MIN_PRINTERSTICKY)
{
bResult = BGetDevmodeSettingForOEM(
pPDev->pdm,
(DWORD)dwIndex,
pOutput,
cbSize,
pcbNeeded);
if (bResult)
*pdwOptionsReturned = 1;
}
else if (dwIndex >= OEMGDS_MIN_PRINTERSTICKY && dwIndex < OEMGDS_MAX)
{
bResult = BGetPrinterDataSettingForOEM(
&pPDev->PrinterData,
(DWORD)dwIndex,
pOutput,
cbSize,
pcbNeeded);
if (bResult)
*pdwOptionsReturned = 1;
}
else
{
bResult = BGetGenericOptionSettingForOEM(
pPDev->pUIInfo,
pPDev->pOptionsArray,
pFeatureKeyword,
pOutput,
cbSize,
pcbNeeded,
pdwOptionsReturned);
}
return bResult;
}
BOOL
BGetStandardVariable(
PDEV *pPDev,
DWORD dwIndex,
PVOID pBuffer,
DWORD cbSize,
PDWORD pcbNeeded
)
/*++
Routine Description:
Provide OEM plugins access to driver private settings
Arguments:
pDev - Points to our device data structure
dwIndex - an index into the arStdPtr array defined in pdev.h and gpd.h
pBuffer - the data is returned in this buffer
cbSize - size of the pBuffer
pcbNeeded - number of bytes actually written into pBuffer
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
BOOL bResult = FALSE;
DWORD dwData;
if (dwIndex >= SVI_MAX) // how could a DWORD be < 0?
{
ERR(("Index must be >= 0 or < SVI_MAX \n"));
return( FALSE);
}
else
{
if(!pcbNeeded)
{
ERR(("pcbNeeded must not be NULL \n"));
return( FALSE);
}
*pcbNeeded = sizeof(dwData);
if(!pBuffer)
return(TRUE);
if(*pcbNeeded > cbSize)
return(FALSE);
dwData = *(pPDev->arStdPtrs[dwIndex]);
memcpy( pBuffer, &dwData, *pcbNeeded );
bResult = TRUE;
}
return bResult;
}
BOOL
BGetGPDData(
PDEV *pPDev,
DWORD dwType, // Type of the data
PVOID pInputData, // reserved. Should be set to 0
PVOID pBuffer, // Caller allocated Buffer to be copied
DWORD cbSize, // Size of the buffer
PDWORD pcbNeeded // New Size of the buffer if needed.
)
/*++
Routine Description:
Provide OEM plugins access to GPD data.
Arguments:
pDev - Points to our device data structure
dwType, // Type of the data
at this time
#define GPD_OEMCUSTOMDATA 1
pInputData will be ignored.
In NT6, we will
#define GPD_OEMDATA 2
at which time the caller will supply pInputData
which points to a data specifier , catagory or label.
(Specifics to be determined when we get there.)
pInputData - reserved. Should be set to 0
pBuffer - the data is returned in this buffer
cbSize - size of the pBuffer
pcbNeeded - number of bytes actually written into pBuffer
Return Value:
TRUE if successful, FALSE if there is an error or dwType not
supported
--*/
{
BOOL bResult = FALSE;
DWORD dwData;
if(!pcbNeeded)
{
ERR(("pcbNeeded must not be NULL \n"));
return( FALSE);
}
switch(dwType)
{
case GPD_OEMCUSTOMDATA:
*pcbNeeded = pPDev->pGlobals->dwOEMCustomData ;
if( !pBuffer)
{
return TRUE; // all goes well.
}
if(*pcbNeeded > cbSize)
return FALSE ; // caller supplied buffer too small.
CopyMemory(pBuffer,
pPDev->pGlobals->pOEMCustomData,
*pcbNeeded);
return TRUE; // all goes well.
break;
default:
break;
}
return bResult ;
}
#ifdef WINNT_40
PVOID
DrvMemAllocZ(
ULONG ulSize
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return(MemAllocZ(ulSize));
}
VOID
DrvMemFree(
PVOID pMem
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
MemFree(pMem);
}
LONG
DrvInterlockedIncrement(
PLONG pRef
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ENTER_CRITICAL_SECTION();
++(*pRef);
LEAVE_CRITICAL_SECTION();
return (*pRef);
}
LONG
DrvInterlockedDecrement(
PLONG pRef
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ENTER_CRITICAL_SECTION();
--(*pRef);
LEAVE_CRITICAL_SECTION();
return (*pRef);
}
BOOL
BHandleOEMInitialize(
POEM_PLUGIN_ENTRY pOemEntry,
ULONG ulReason
)
/*++
Routine Description:
Manage reference counting for OEM render plugin DLLs to determine
when plugin's DLLInitliaze() should be called.
This function is supported only for NT4 kernel mode render plugin
DLLs because only in that situation plugin needs to use kernel
semaphore to implement COM's AddRef and Release.
If the plugin DLL is loaded for the first time, call its
DLLInitialize(DLL_PROCESS_ATTACH) so it can initialize its
semaphore.
If the plugin DLL is unloaded by its last client, call its
DLLInitialize(DLL_PROCESS_DETACH) so it can delete its
semaphore.
Arguments:
pOemEntry - Points to information about the OEM plugin
ulReason - either DLL_PROCESS_ATTACH or DLL_PROCESS_DETACH
Return Value:
TRUE is succeeded, FALSE otherwise.
--*/
{
LPFNDLLINITIALIZE pfnDllInitialize;
BOOL bCallDllInitialize;
BOOL bRetVal = TRUE;
if (pOemEntry->hInstance &&
(pfnDllInitialize = (LPFNDLLINITIALIZE)GetProcAddress(
(HMODULE) pOemEntry->hInstance,
(CHAR *) szDllInitialize)))
{
switch (ulReason) {
case DLL_PROCESS_ATTACH:
ENTER_CRITICAL_SECTION();
//
// Managing the global ref count link list must be done
// inside critical section.
//
bCallDllInitialize = BOEMPluginFirstLoad(pOemEntry->ptstrDriverFile,
&gpOEMPluginRefCount);
LEAVE_CRITICAL_SECTION();
if (bCallDllInitialize)
{
//
// The render plugin DLL is loaded for the first time.
//
bRetVal = pfnDllInitialize(ulReason);
}
break;
case DLL_PROCESS_DETACH:
ENTER_CRITICAL_SECTION();
//
// Managing the global ref count link list must be done
// inside critical section.
//
bCallDllInitialize = BOEMPluginLastUnload(pOemEntry->ptstrDriverFile,
&gpOEMPluginRefCount);
LEAVE_CRITICAL_SECTION();
if (bCallDllInitialize)
{
//
// The render plugin DLL is unloaded by its last client.
//
bRetVal = pfnDllInitialize(ulReason);
}
break;
default:
ERR(("BHandleOEMInitialize is called with an unknown ulReason.\n"));
break;
}
}
return bRetVal;
}
#endif // WINNT_40