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.
619 lines
12 KiB
619 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1990-2003 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
cachegpc.c
|
|
|
|
|
|
Abstract:
|
|
|
|
This module contains functions to cached the PLOTGPC
|
|
|
|
|
|
Author:
|
|
|
|
15-Dec-1993 Wed 20:29:07 created
|
|
|
|
|
|
[Environment:]
|
|
|
|
GDI Device Driver - Plotter.
|
|
|
|
|
|
[Notes:]
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define DBG_PLOTFILENAME DbgCacheGPC
|
|
|
|
#define DBG_CACHE_DATA 0x00000001
|
|
#define DBG_CS 0x00000002
|
|
#define DBG_FORCE_UPDATE 0x80000000
|
|
|
|
|
|
DEFINE_DBGVAR(0);
|
|
|
|
|
|
//
|
|
// Local structrue and definitions only used in this module
|
|
//
|
|
|
|
typedef struct _CACHEDPLOTGPC {
|
|
struct _CACHEDPLOTGPC *pNext;
|
|
DWORD cRef;
|
|
PPLOTGPC pPlotGPC;
|
|
WCHAR wszFile[1];
|
|
} CACHEDPLOTGPC, *PCACHEDPLOTGPC;
|
|
|
|
#define MAX_CACHED_PLOTGPC 16
|
|
|
|
|
|
DWORD cCachedGPC = 0;
|
|
PCACHEDPLOTGPC pCHead = NULL;
|
|
|
|
#if defined(UMODE) || defined(USERMODE_DRIVER)
|
|
|
|
CRITICAL_SECTION CachedGPCDataCS;
|
|
|
|
#define ACQUIREGPCSEM() EnterCriticalSection(&CachedGPCDataCS)
|
|
|
|
#define RELEASEGPCSEM() LeaveCriticalSection(&CachedGPCDataCS)
|
|
|
|
#define CREATEGPCSEM() InitializeCriticalSection(&CachedGPCDataCS)
|
|
|
|
#define DELETEGPCSEM() DeleteCriticalSection(&CachedGPCDataCS)
|
|
|
|
#else
|
|
|
|
HSEMAPHORE hsemGPC = NULL;
|
|
|
|
#define ACQUIREGPCSEM() EngAcquireSemaphore(hsemGPC)
|
|
#define RELEASEGPCSEM() EngReleaseSemaphore(hsemGPC)
|
|
#define CREATEGPCSEM() hsemGPC = EngCreateSemaphore()
|
|
#define DELETEGPCSEM() EngDeleteSemaphore(hsemGPC)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
InitCachedData(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initialized the GPC data cache
|
|
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
Author:
|
|
|
|
12-May-1994 Thu 11:50:04 created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PLOTDBG(DBG_CS, ("InitCachedData: InitCriticalSection, Count=%ld, pCHead=%08lx",
|
|
cCachedGPC, pCHead));
|
|
|
|
cCachedGPC = 0;
|
|
pCHead = NULL;
|
|
|
|
try {
|
|
|
|
CREATEGPCSEM();
|
|
|
|
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|
//
|
|
// Critical section failed to get initialized.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DestroyCachedData(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function destroy all the cached information for PPRINTERINFO
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
|
|
Author:
|
|
|
|
15-Dec-1993 Wed 20:30:16 38:27 created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
try {
|
|
|
|
PCACHEDPLOTGPC pTemp;
|
|
|
|
|
|
PLOTDBG(DBG_CS, ("DestroyCachedData: EnterCriticalSection, TOT=%ld",
|
|
cCachedGPC));
|
|
|
|
ACQUIREGPCSEM();
|
|
|
|
while (pCHead) {
|
|
|
|
PLOTDBG(DBG_CACHE_DATA, ("!!!DESTROY cached pPlotGPC=[%p] %s",
|
|
(DWORD_PTR)pCHead->pPlotGPC, pCHead->wszFile));
|
|
|
|
PLOTASSERT(1, "DestroyCachedData: cCachedGPC <= 0, pCHead=%08lx",
|
|
cCachedGPC > 0, pCHead);
|
|
|
|
pTemp = pCHead;
|
|
pCHead = pCHead->pNext;
|
|
|
|
--cCachedGPC;
|
|
|
|
LocalFree((HLOCAL)pTemp->pPlotGPC);
|
|
LocalFree((HLOCAL)pTemp);
|
|
}
|
|
|
|
} finally {
|
|
|
|
|
|
PLOTDBG(DBG_CS, ("DestroyCachedData: LeaveCriticalSection"));
|
|
|
|
RELEASEGPCSEM();
|
|
|
|
PLOTDBG(DBG_CS, ("DestroyCachedData: DeleteCriticalSection"));
|
|
|
|
DELETEGPCSEM();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
UnGetCachedPlotGPC(
|
|
PPLOTGPC pPlotGPC
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function un-reference a used cached GPC object
|
|
|
|
Arguments:
|
|
|
|
pPlotGPC - Pointer to the cached GPC returned from GetCachedPlotGPC
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
|
|
|
|
Author:
|
|
|
|
10-May-1994 Tue 16:27:15 created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL Ok = FALSE;
|
|
|
|
|
|
try {
|
|
|
|
PCACHEDPLOTGPC pCur;
|
|
|
|
|
|
PLOTDBG(DBG_CS, ("UnGetCachedPlotGPC: EnterCriticalSection"));
|
|
|
|
ACQUIREGPCSEM();
|
|
|
|
pCur = pCHead;
|
|
|
|
while (pCur) {
|
|
|
|
if (pCur->pPlotGPC == pPlotGPC) {
|
|
|
|
//
|
|
// Found it, move that to the front and return pPlotGPC
|
|
//
|
|
|
|
PLOTDBG(DBG_CACHE_DATA, ("UnGetCachedPlotGPC: TOT=%ld, Found Cached pPlotGPC=%08lx, cRef=%ld->%ld, <%s>",
|
|
cCachedGPC, pCur->pPlotGPC, pCur->cRef,
|
|
pCur->cRef - 1, pCur->wszFile));
|
|
|
|
if (pCur->cRef) {
|
|
|
|
--(pCur->cRef);
|
|
|
|
} else {
|
|
|
|
PLOTWARN(("UnGetCachedPlotGPC(): Ref Count == 0 already???"));
|
|
}
|
|
|
|
Ok = TRUE;
|
|
|
|
//
|
|
// Exit Now
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
pCur = pCur->pNext;
|
|
}
|
|
|
|
if (!Ok) {
|
|
|
|
PLOTERR(("UnGetCachedPlotGPC(): pPlotGPC=%08lx not found!", pPlotGPC));
|
|
}
|
|
|
|
} finally {
|
|
|
|
PLOTDBG(DBG_CS, ("UnGetCachedPlotGPC: LeaveCriticalSection"));
|
|
|
|
RELEASEGPCSEM();
|
|
}
|
|
|
|
return(Ok);
|
|
}
|
|
|
|
|
|
|
|
|
|
PPLOTGPC
|
|
GetCachedPlotGPC(
|
|
LPWSTR pwDataFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function return cached PlotGPC pointer, if not cached then it will
|
|
add it to the cached, if cached data is full it will delete least used one
|
|
first.
|
|
|
|
Arguments:
|
|
|
|
pwDataFile - Pointe to the data file
|
|
|
|
Return Value:
|
|
|
|
pPlotGPC, NULL if failed
|
|
|
|
|
|
Author:
|
|
|
|
15-Dec-1993 Wed 20:30:25 created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PPLOTGPC pPlotGPC = NULL;
|
|
|
|
|
|
try {
|
|
|
|
PCACHEDPLOTGPC pCur;
|
|
PCACHEDPLOTGPC pPrev;
|
|
UINT Idx;
|
|
|
|
|
|
PLOTDBG(DBG_CS, ("GetCachedPlotGPC: EnterCriticalSection"));
|
|
|
|
ACQUIREGPCSEM();
|
|
|
|
pCur = pCHead;
|
|
pPrev = NULL;
|
|
|
|
//
|
|
// Traverse through the linked list, and exit when at end, remember if
|
|
// we have more than 2 in the cached then we want to preserved last
|
|
// pPrev, so we know the pPrev of the last one, (because we need to
|
|
// delete last one)
|
|
//
|
|
|
|
while (pCur) {
|
|
|
|
if (!_wcsicmp(pCur->wszFile, pwDataFile)) {
|
|
|
|
//
|
|
// Found it, move that to the front and return pPlotGPC
|
|
//
|
|
|
|
if (pPrev) {
|
|
|
|
pPrev->pNext = pCur->pNext;
|
|
pCur->pNext = pCHead;
|
|
pCHead = pCur;
|
|
}
|
|
|
|
PLOTDBG(DBG_CACHE_DATA,
|
|
("GetCachedPlotGPC: TOT=%ld, FOUND [%08lx], cRef=%ld->%ld, <%s>",
|
|
cCachedGPC, pCur->pPlotGPC, pCur->cRef,
|
|
pCur->cRef + 1, pCur->wszFile));
|
|
#if DBG
|
|
if (DBG_PLOTFILENAME & DBG_FORCE_UPDATE) {
|
|
|
|
LocalFree((HLOCAL)(pCur->pPlotGPC));
|
|
pCur->pPlotGPC =
|
|
pPlotGPC = ReadPlotGPCFromFile(pwDataFile);
|
|
|
|
PLOTDBG(DBG_FORCE_UPDATE,
|
|
("GetCachedPlotGPC: ForceUpdate: pPlotGPC=%08lx: %s",
|
|
pPlotGPC, pCur->wszFile));
|
|
}
|
|
#endif
|
|
++(pCur->cRef);
|
|
pPlotGPC = pCur->pPlotGPC;
|
|
|
|
break;
|
|
}
|
|
|
|
pPrev = pCur;
|
|
pCur = pCur->pNext;
|
|
}
|
|
|
|
//
|
|
// If we have too many entries in the cache then delete them to fit
|
|
// into the MAX_CACHED_PLOTGPC, delete the oldest one first
|
|
//
|
|
|
|
if (cCachedGPC > MAX_CACHED_PLOTGPC) {
|
|
|
|
PCACHEDPLOTGPC pFree[MAX_CACHED_PLOTGPC];
|
|
|
|
|
|
pPrev = NULL;
|
|
pCur = pCHead;
|
|
Idx = 0;
|
|
|
|
while ((pCur) && (Idx < MAX_CACHED_PLOTGPC)) {
|
|
|
|
if (pCur->cRef == 0) {
|
|
|
|
pFree[Idx++] = pPrev;
|
|
}
|
|
|
|
pPrev = pCur;
|
|
pCur = pCur->pNext;
|
|
}
|
|
|
|
while ((cCachedGPC > MAX_CACHED_PLOTGPC) && (Idx--)) {
|
|
|
|
if (pPrev = pFree[Idx]) {
|
|
|
|
pCur = pPrev->pNext;
|
|
pPrev->pNext = pPrev->pNext->pNext;
|
|
|
|
} else {
|
|
|
|
pCur = pCHead;
|
|
pCHead = pCHead->pNext;
|
|
}
|
|
|
|
PLOTDBG(DBG_CACHE_DATA,
|
|
("Cached Full=%ld, DELETE: 1pCur=%08lx, pPlotGPC=%08lx <%s>",
|
|
cCachedGPC, pCur, pCur->pPlotGPC, pCur->wszFile));
|
|
|
|
--cCachedGPC;
|
|
|
|
LocalFree((HLOCAL)pCur->pPlotGPC);
|
|
LocalFree((HLOCAL)pCur);
|
|
}
|
|
}
|
|
|
|
if (!pPlotGPC) {
|
|
|
|
PLOTDBG(DBG_CACHE_DATA,("GPC cached NOT FOUND for %s", pwDataFile));
|
|
|
|
//
|
|
// Read the New pPlotGPC, and add that to the linked list, make
|
|
// it as most recent used (at the Head)
|
|
//
|
|
|
|
if (pPlotGPC = ReadPlotGPCFromFile(pwDataFile)) {
|
|
|
|
SIZE_T cchDataFile;
|
|
|
|
cchDataFile = wcslen(pwDataFile) + 1;
|
|
|
|
Idx = (UINT)((cchDataFile * sizeof(WCHAR)) +
|
|
sizeof(CACHEDPLOTGPC));
|
|
|
|
if (pCur = (PCACHEDPLOTGPC)LocalAlloc(LMEM_FIXED, Idx)) {
|
|
|
|
//
|
|
// Setting all the fields to the new NODE, and make this
|
|
// node as the head of the linked list
|
|
//
|
|
|
|
if (SUCCEEDED(StringCchCopyW(pCur->wszFile, cchDataFile, pwDataFile)))
|
|
{
|
|
pCur->pNext = pCHead;
|
|
pCur->cRef = 1;
|
|
pCur->pPlotGPC = pPlotGPC;
|
|
pCHead = pCur;
|
|
|
|
//
|
|
// Said we have one more in the cache
|
|
//
|
|
|
|
++cCachedGPC;
|
|
|
|
PLOTDBG(DBG_CACHE_DATA,
|
|
("GetCachedPlotGPC: TOT=%ld, cRef=0->1, ADD CACHED pPlotGPC=%08lx <%s>",
|
|
cCachedGPC, pCur->pPlotGPC, pCur->wszFile));
|
|
}
|
|
else
|
|
{
|
|
PLOTERR(("GetCachedPlotGPC: StringCchCopyW failed"));
|
|
|
|
LocalFree((HLOCAL)pCur);
|
|
pCur = NULL;
|
|
|
|
LocalFree((HLOCAL)pPlotGPC);
|
|
pPlotGPC = NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
PLOTERR(("GetCachedPlotGPC: LocalAlloc(%ld)) failed", Idx));
|
|
|
|
LocalFree((HLOCAL)pPlotGPC);
|
|
pPlotGPC = NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
PLOTERR(("GetCachedPlotGPC: ReadPlotGPCFormFile(%s) failed",
|
|
pwDataFile));
|
|
}
|
|
}
|
|
|
|
} finally {
|
|
|
|
PLOTDBG(DBG_CS, ("GetCachedPlotGPC: LeaveCriticalSection"));
|
|
|
|
RELEASEGPCSEM();
|
|
}
|
|
|
|
return(pPlotGPC);
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef UMODE
|
|
|
|
|
|
PPLOTGPC
|
|
hPrinterToPlotGPC(
|
|
HANDLE hPrinter,
|
|
LPWSTR pwDeviceName,
|
|
size_t cchDeviceName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function return cached PlotGPC pointer and it also return the device
|
|
name
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Handle to the printer interested
|
|
|
|
pwDataFile - Pointe to the data file
|
|
|
|
pwDeviceName - Pointer to the dmDeviceName where the name will be
|
|
stored if this pointer is not NULL
|
|
|
|
Return Value:
|
|
|
|
pPlotGPC, NULL if failed
|
|
|
|
|
|
Author:
|
|
|
|
15-Dec-1993 Wed 20:30:25 created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DRIVER_INFO_2 *pDI2;
|
|
PPLOTGPC pPlotGPC;
|
|
|
|
|
|
if (!(pDI2 = (DRIVER_INFO_2 *)GetDriverInfo(hPrinter, 2))) {
|
|
|
|
PLOTERR(("GetCachedPlotGPC: GetDriverInfo(DRIVER_INFO_2) failed"));
|
|
return(NULL);
|
|
}
|
|
|
|
if (pwDeviceName) {
|
|
|
|
size_t cchSize;
|
|
|
|
if (cchDeviceName < CCHDEVICENAME)
|
|
{
|
|
cchSize = cchDeviceName;
|
|
}
|
|
else
|
|
{
|
|
cchSize = CCHDEVICENAME;
|
|
}
|
|
_WCPYSTR(pwDeviceName, pDI2->pName, cchSize);
|
|
}
|
|
|
|
pPlotGPC = GetCachedPlotGPC(pDI2->pDataFile);
|
|
|
|
LocalFree((HLOCAL)pDI2);
|
|
|
|
return(pPlotGPC);
|
|
}
|
|
|
|
#endif
|