Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

635 lines
16 KiB

/******************************Module*Header*******************************\
* Module Name: ldevobj.cxx *
* *
* Copyright (c) 1990-1994 Microsoft Corporation *
* *
* Pointers and locking are hidden in these objects. *
\**************************************************************************/
#include "precomp.hxx"
#define ENABLE_FUNC_NAME "DrvEnableDriver"
/******************************Member*Function*****************************\
* LDEVREF::LDEVREF (pszDriver,ldt)
*
* Locate an existing driver or load a new one. Increase its reference
* count.
*
\**************************************************************************/
LDEVREF::LDEVREF(PWSZ pwszDriver, LDEVTYPE ldt) : XLDEVOBJ()
{
TRACE_INIT(("LDEVREF::LDEVREF: ENTERING\n"));
BOOL bLoaded;
//
// Assume failure.
//
pldev = NULL;
//
// Check for a bogus driver name.
//
if ((pwszDriver == (PWSZ) NULL) ||
(*pwszDriver == L'\0'))
{
WARNING("gdisrv!LDEVREF(): bogus driver name\n");
return;
}
#if DBG
//
// Check for bogus driver type
//
if ((ldt != LDEV_FONT) &&
(ldt != LDEV_DEVICE_DISPLAY) &&
(ldt != LDEV_DEVICE_PRINTER))
{
WARNING("gdisrv!LDEVREF(): bad LDEVTYPE\n");
return;
}
#endif
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
pldev = ldevLoadImage(pwszDriver, FALSE, &bLoaded);
if (pldev)
{
if (bLoaded)
{
TRACE_INIT(("LDEVREF::LDEVREF: SUCCESS, Driver already loaded\n"));
return;
}
else
{
DRVENABLEDATA ded = {0,0,(DRVFN *) NULL};
if ((pldev->pGdiDriverInfo->EntryPoint != NULL) &&
((PFN_DrvEnableDriver) pldev->pGdiDriverInfo->EntryPoint)(
ENGINE_VERSION, sizeof(DRVENABLEDATA), &ded) &&
(ded.iDriverVersion <= ENGINE_VERSION) &&
(ded.iDriverVersion >= ENGINE_VERSIONSUR) &&
bFillTable(ded))
{
//
// Make sure the name and type of the ldev is initialized
//
pldev->ldevType = ldt;
TRACE_INIT(("LDEVREF::LDEVREF: SUCCESS\n"));
return;
}
else
{
//
// Error exit path
//
ldevUnloadImage(pldev);
pldev = NULL;
TRACE_INIT(("LDEVREF::LDEVREF: FAILIURE\n"));
return;
}
}
}
}
/******************************Member*Function*****************************\
* LDEVREF::LDEVREF
*
* Enable one of the statically linked font drivers via the LDEV.
*
\**************************************************************************/
LDEVREF::LDEVREF(PFN pfnEnable,LDEVTYPE ldt) : XLDEVOBJ()
{
//
// Assume failure.
//
TRACE_INIT(("LDEVREF::LDEVREF: loading static font\n"));
//
// Allocate memory for the LDEV.
//
pldev = (LDEV *) PALLOCMEM(sizeof(LDEV), 'vdlG');
if (pldev == NULL)
{
WARNING("LDEV failed to allocate memory\n");
return;
}
//
// Call the Enable entry point.
//
DRVENABLEDATA ded;
if (!((* (PFN_DrvEnableDriver) pfnEnable) (ENGINE_VERSION,sizeof(DRVENABLEDATA),&ded)))
{
VFREEMEM(pldev);
pldev = NULL;
WARNING("Static font driver init failed\n");
return;
}
pldev->ldevType = ldt;
pldev->cRefs = 1;
bFillTable(ded);
//
// Initialize the rest of the LDEV.
//
if (gpldevDrivers)
{
gpldevDrivers->pldevPrev = pldev;
}
pldev->pldevNext = gpldevDrivers;
pldev->pldevPrev = NULL;
gpldevDrivers = pldev;
//
// Since this driver is statically linked in, there is no name or
// MODOBJ.
//
pldev->pGdiDriverInfo = NULL;
TRACE_INIT(("LDEVREF::LDEVREF: SUCCESS loaded static font\n"));
}
/******************************Member*Function*****************************\
* LDEVREF::bFillTable (ded)
*
* Fills the dispatch table of the LDEV with function pointers from the
* driver. Checks that the required functions are present.
*
\**************************************************************************/
#if DBG
static const ULONG aiFuncRequired[] =
{
INDEX_DrvEnablePDEV,
INDEX_DrvCompletePDEV,
INDEX_DrvDisablePDEV,
};
static const ULONG aiFuncPairs[][2] =
{
{INDEX_DrvCreateDeviceBitmap,INDEX_DrvDeleteDeviceBitmap}
};
static const ULONG aiFuncRequiredFD[] =
{
INDEX_DrvQueryFont,
INDEX_DrvQueryFontTree,
INDEX_DrvQueryFontData,
INDEX_DrvQueryFontCaps,
INDEX_DrvLoadFontFile,
INDEX_DrvUnloadFontFile,
INDEX_DrvQueryFontFile
};
#endif
BOOL LDEVREF::bFillTable(DRVENABLEDATA& ded)
{
//
// Get local copies of ded info and a pointer to the dispatch table.
//
ULONG cLeft = ded.c;
PDRVFN pdrvfn = ded.pdrvfn;
PFN *ppfnTable = pldev->apfn;
//
// Store the driver version in the LDEV
//
pldev->ulDriverVersion = ded.iDriverVersion;
//
// fill with zero pointers to avoid possibility of accessing
// incorrect fields later
//
RtlZeroMemory(ppfnTable, INDEX_LAST*sizeof(PFN));
//
// Copy driver functions into our table.
//
while (cLeft--)
{
//
// Check the range of the index.
//
if (pdrvfn->iFunc >= INDEX_LAST)
{
ASSERTGDI(FALSE,"bFillTableLDEVREF(): bogus function index\n");
return(FALSE);
}
//
// Copy the pointer.
//
ppfnTable[pdrvfn->iFunc] = pdrvfn->pfn;
pdrvfn++;
}
#if DBG
//
// Check for required driver functions.
//
cLeft = sizeof(aiFuncRequired) / sizeof(ULONG);
while (cLeft--)
{
if (ppfnTable[aiFuncRequired[cLeft]] == (PFN) NULL)
{
ASSERTGDI(FALSE,"bFillTableLDEVREF(): a required function is missing from driver\n");
return(FALSE);
}
}
//
// Check for required font functions.
//
if (pldev->ldevType == LDEV_FONT)
{
cLeft = sizeof(aiFuncRequiredFD) / sizeof(ULONG);
while (cLeft--)
{
if (ppfnTable[aiFuncRequiredFD[cLeft]] == (PFN) NULL)
{
ASSERTGDI(FALSE,"bFillTable(): a required FD function is missing\n");
return(FALSE);
}
}
}
//
// Check for functions that come in pairs.
//
cLeft = sizeof(aiFuncPairs) / sizeof(ULONG) / 2;
while (cLeft--)
{
//
// Make sure that either both functions are hooked or both functions
// are not hooked.
//
if ((ppfnTable[aiFuncPairs[cLeft][0]] == (PFN) NULL)
!= (ppfnTable[aiFuncPairs[cLeft][1]] == (PFN) NULL))
{
ASSERTGDI(FALSE,"bFillTableLDEVREF(): one of pair of functions is missing from driver\n");
return(FALSE);
}
}
#endif
return(TRUE);
}
/******************************Member*Function*****************************\
* LDEVREF::~LDEVREF ()
*
* Unlocks and possibly unload an LDEV.
*
\**************************************************************************/
LDEVREF::~LDEVREF()
{
TRACE_INIT(("LDEVREF::~LDEVREF: ENTERING\n"));
if (pldev != NULL)
{
//
// Grab the semaphore th make sure everything is OK.
//
SEMOBJ so(gpsemDriverMgmt);
ldevUnloadImage(pldev);
}
TRACE_INIT(("LDEVREF::~LDEVREF: SUCCESS\n"));
}
/******************************Member*Function*****************************\
* PLDEV FindImage(PUNICODE_STRING pstrDriver)
*
* Determines if an image is already in the LDEV list.
*
\**************************************************************************/
PLDEV
ldevLoadImage(
PWSZ pwszDriver,
BOOL bImage,
PBOOL pbAlreadyLoaded
)
{
PSYSTEM_GDI_DRIVER_INFORMATION pGdiDriverInfo = NULL;
PLDEV pldev = NULL;
UNICODE_STRING usDriverName;
PLDEV pldevList;
NTSTATUS Status;
BOOLEAN OldHardErrorMode;
TRACE_INIT(("ldevLoadImage called on Image %ws\n", pwszDriver));
*pbAlreadyLoaded = FALSE;
//
// Only append the .dll if it's NOT an image.
//
if (MakeSystemRelativePath(pwszDriver,
&usDriverName,
!bImage))
{
//
// Check both list of drivers.
//
VACQUIRESEM(gpsemDriverMgmt);
pldevList = gpldevDrivers;
TRACE_INIT(("ldevLoadImage - search for existing image %ws\n",
usDriverName.Buffer));
while (pldevList != NULL)
{
//
// If there is a valid driver image, and if the types are compatible.
// bImage == TRUE means load an image, while bImage == FALSE means
// anything else (for now)
//
if ((pldevList->pGdiDriverInfo) &&
((pldevList->ldevType == LDEV_IMAGE) == bImage))
{
//
// Do a case insensitive compare since the printer driver name
// can come from different locations.
//
if (RtlEqualUnicodeString(&(pldevList->pGdiDriverInfo->DriverName),
&usDriverName,
TRUE))
{
//
// If it's already loaded, increment the ref count
// and return that pointer.
//
TRACE_INIT(("ldevLoadImage found image. Inc ref count\n"));
pldevList->cRefs++;
*pbAlreadyLoaded = TRUE;
pldev = pldevList;
break;
}
}
pldevList = pldevList->pldevNext;
}
if (pldev == NULL)
{
TRACE_INIT(("ldevLoadImage - try to load new iamge\n"));
pGdiDriverInfo = (PSYSTEM_GDI_DRIVER_INFORMATION)
PALLOCNOZ(sizeof(SYSTEM_GDI_DRIVER_INFORMATION), 'idSG');
pldev = (PLDEV) PALLOCMEM(sizeof(LDEV), 'vdlG');
if (pGdiDriverInfo && pldev)
{
TRACE_INIT(("ldevLoadImage attempting to load new image\n"));
pGdiDriverInfo->DriverName = usDriverName;
//
// We must disable hard error popups when loading drivers.
// Otherwise we will deadlock since MM will directly try to put
// up a popup.
//
// This will also stop us from automatically bugchecking when
// an old driver is loaded, so we can try and recvoder from it.
//
// BUGBUG we want to put up our own popup if this occurs.
// It needs to be done higher up when we have no locks held.
//
OldHardErrorMode = PsGetCurrentThread()->HardErrorsAreDisabled;
PsGetCurrentThread()->HardErrorsAreDisabled = TRUE;
Status = ZwSetSystemInformation(SystemLoadGdiDriverInformation,
pGdiDriverInfo,
sizeof(SYSTEM_GDI_DRIVER_INFORMATION));
PsGetCurrentThread()->HardErrorsAreDisabled = OldHardErrorMode;
if (NT_SUCCESS(Status))
{
TRACE_INIT(("ldevLoadImage SUCCESS with HANDLE %08lx\n",
(ULONG)pGdiDriverInfo));
pldev->pGdiDriverInfo = pGdiDriverInfo;
pldev->cRefs = 1;
// Assume image for now.
pldev->ldevType = LDEV_IMAGE;
pldev->ulDriverVersion = (ULONG) -1;
if (gpldevDrivers)
{
gpldevDrivers->pldevPrev = pldev;
}
pldev->pldevNext = gpldevDrivers;
pldev->pldevPrev = NULL;
gpldevDrivers = pldev;
//
// We exit with all resources allocated, after leaving the
// semaphore.
//
VRELEASESEM(gpsemDriverMgmt);
return (pldev);
}
else
{
//
// Check the special return code from MmLoadSystemImage
// that indicates this is an old driver being linked
// against something else than win32k.sys
//
// If it is, call user to log the error.
if (Status == STATUS_PROCEDURE_NOT_FOUND)
{
UserLogDisplayDriverEvent(MsgInvalidOldDriver);
}
}
}
//
// Either success due to a cached entry, or failiure.
// In either case, we can free all the resources we allocatred.
//
if (pGdiDriverInfo)
VFREEMEM(pGdiDriverInfo);
if (pldev)
VFREEMEM(pldev);
pldev = NULL;
}
VRELEASESEM(gpsemDriverMgmt);
VFREEMEM(usDriverName.Buffer);
}
TRACE_INIT(("ldevLoadImage %ws with HANDLE %08lx\n",
pldev ? L"SUCCESS" : L"FAILED", pldev));
return (pldev);
}
/******************************Member*Function*****************************\
* ldevUnloadImage()
*
* Deletes an LDEV. Disables and unloads the driver.
*
* The reference count must be zero when this function is called.
*
\**************************************************************************/
VOID
ldevUnloadImage(
PLDEV pldev
)
{
//
// Hold the LDEV semaphore until after the module is unloaded.
//
VACQUIRESEM(gpsemDriverMgmt);
if (--pldev->cRefs == 0)
{
//
// Make sure that there is exactly one reference to this LDEV.
//
ASSERTGDI(pldev->cRefs == 0, "ldevUnloadImage Ref Count not 0");
TRACE_INIT(("LDEVREF::bDelete: ENTERING\n"));
//
// If the module handle exits, need to unload the module. (Does not exist
// for the statically linked font drivers).
//
if (pldev->pGdiDriverInfo)
{
//
// Disable the driver.
//
TRACE_INIT(("LDEVREF::bDelete: calling the driver to unload\n"));
//
// Tell the module to unload.
//
TRACE_INIT(("ldevUnloadImage called on Image %08lx, \n %ws\n",
(ULONG) pldev, pldev->pGdiDriverInfo->DriverName.Buffer));
ZwSetSystemInformation(SystemUnloadGdiDriverInformation,
&(pldev->pGdiDriverInfo->SectionPointer),
sizeof(ULONG));
//
// Free the memory associate with the module
//
VFREEMEM(pldev->pGdiDriverInfo->DriverName.Buffer);
VFREEMEM(pldev->pGdiDriverInfo);
}
//
// Remove the ldev from the linker list
//
if (pldev->pldevNext)
{
pldev->pldevNext->pldevPrev = pldev->pldevPrev;
}
if (pldev->pldevPrev)
{
pldev->pldevPrev->pldevNext = pldev->pldevNext;
}
else
{
gpldevDrivers = pldev->pldevNext;
}
//
// Free the ldev
//
VFREEMEM(pldev);
}
else
{
TRACE_INIT(("ldevUnloadImage - refcount decremented\n"));
}
VRELEASESEM(gpsemDriverMgmt);
return;
}