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.
806 lines
23 KiB
806 lines
23 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: cleanup.cxx
|
|
*
|
|
* Process termination - this file cleans up objects when a process
|
|
* terminates.
|
|
*
|
|
* Created: 22-Jul-1991 12:24:52
|
|
* Author: Eric Kutter [erick]
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
#include "muclean.hxx"
|
|
|
|
extern BOOL bDeleteBrush(HBRUSH,BOOL); // brushobj.cxx
|
|
extern VOID vCleanupPrivateFonts(); // pftobj.cxx
|
|
|
|
extern HCOLORSPACE ghStockColorSpace; // icmapi.cxx
|
|
|
|
#if DBG
|
|
ULONG
|
|
DbgPrint(
|
|
PCH Format,
|
|
...
|
|
);
|
|
#define DBGPRINT(x) DbgPrint(x)
|
|
#else
|
|
#define DBGPRINT(x)
|
|
#endif
|
|
|
|
ULONG gInitialBatchCount = 0x14;
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 24-Jul-1991 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vCleanupDCs(W32PID pid)
|
|
{
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, pid))
|
|
{
|
|
if (HmgObjtype(hobj) == DC_TYPE)
|
|
{
|
|
HmgSetLock(hobj, 0);
|
|
bDeleteDCInternal((HDC)hobj,TRUE,TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* Sat 20-Jun-1992 -by- Patrick Haluptzok [patrickh]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vCleanupBrushes(W32PID pid)
|
|
{
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, pid))
|
|
{
|
|
if (HmgObjtype(hobj) == BRUSH_TYPE)
|
|
{
|
|
bDeleteBrush((HBRUSH)hobj,TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* Sat 20-Jun-1992 -by- Patrick Haluptzok [patrickh]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vCleanupSurfaces(W32PID pid, CLEANUPTYPE cutype)
|
|
{
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, pid))
|
|
{
|
|
if (HmgObjtype(hobj) == SURF_TYPE)
|
|
{
|
|
SURFREF so((HSURF)hobj);
|
|
|
|
//
|
|
// Skip PDEV surfaces; they are cleaned up with the PDEV
|
|
// (see PDEVOBJ::vUnreferencePdev and PDEVOBJ::vDisableSurface).
|
|
//
|
|
// Also cleanup if this is a UMPD surface. This is to handle the
|
|
// case when a DrvDisableSurface call to usermode printer driver
|
|
// is nuked due to a terminate APC and we start process GDI cleanup.
|
|
// If we did not have the || so.ps->bUMPD() we will leak the handle.
|
|
|
|
if (!so.ps->bPDEVSurface() || so.ps->bUMPD())
|
|
so.bDeleteSurface(cutype);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 24-Jul-1991 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vCleanupFonts(W32PID pid)
|
|
{
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, pid))
|
|
{
|
|
if (HmgObjtype(hobj) == LFONT_TYPE)
|
|
{
|
|
bDeleteFont((HLFONT) hobj, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vCleanupLCSPs
|
|
*
|
|
* History:
|
|
*
|
|
* 9/20/1996 Mark Enstrom [marke]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vCleanupLCSPs(W32PID pid)
|
|
{
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, pid))
|
|
{
|
|
if (HmgObjtype(hobj) == ICMLCS_TYPE)
|
|
{
|
|
bDeleteColorSpace((HCOLORSPACE)hobj);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Eliminate user pregion to make sure delete succceds
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vCleanupRegions(W32PID pid)
|
|
{
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, pid))
|
|
{
|
|
if (HmgObjtype(hobj) == RGN_TYPE)
|
|
{
|
|
RGNOBJ ro;
|
|
|
|
ro.prgn = (PREGION)HmgLock(hobj,RGN_TYPE);
|
|
|
|
if (ro.prgn)
|
|
{
|
|
PENTRY pent = PENTRY_FROM_POBJ(ro.prgn);
|
|
|
|
if (pent)
|
|
{
|
|
pent->pUser = NULL;
|
|
}
|
|
|
|
DEC_EXCLUSIVE_REF_CNT(ro.prgn);
|
|
}
|
|
else
|
|
{
|
|
WARNING("vCleanupRegions: locked region has bad pEntry");
|
|
}
|
|
|
|
bDeleteRegion((HRGN)hobj);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 01-Feb-2001 -by- Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vRemoveRefPalettes(W32PID pid)
|
|
{
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, pid))
|
|
{
|
|
if (HmgObjtype(hobj) == PAL_TYPE)
|
|
{
|
|
SEMOBJ semo(ghsemPalette);
|
|
|
|
EPALOBJ palobj((HPALETTE)hobj);
|
|
palobj.apalResetColorTable();
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 07-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bEnumFontClose(ULONG_PTR ulEnum)
|
|
{
|
|
EFSOBJ efso((HEFS) ulEnum);
|
|
|
|
if (!efso.bValid())
|
|
{
|
|
WARNING("gdisrv!bDeleteFontEnumState(): bad HEFS handle\n");
|
|
return FALSE;
|
|
}
|
|
|
|
efso.vDeleteEFSOBJ();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiInit()
|
|
*
|
|
* This routine must be called before any other GDI routines. Currently
|
|
* it doesn't actualy do anything, just forces a kernel mode transition
|
|
* which will cause GdiProcessCallout to get called.
|
|
*
|
|
* History:
|
|
* 07-Sep-1995 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL NtGdiInit()
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiCloseProcess
|
|
*
|
|
* Release the resources held by the specified process.
|
|
*
|
|
* The cutype is set to CLEANUP_SESSION only for MultiUserGreCleanup
|
|
* (Hydra) processing. It is used to do extra work to allow cleanup
|
|
* of cross-process data not normally cleaned up on process termination,
|
|
* just GRE termination (e.g., global and default data such as the
|
|
* default bitmap and the public font tables).
|
|
*
|
|
* History:
|
|
* 03-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL FASTCALL
|
|
NtGdiCloseProcess(W32PID W32Pid, CLEANUPTYPE cutype)
|
|
{
|
|
BOOL bRes = TRUE;
|
|
|
|
ASSERTGDI(cutype != CLEANUP_NONE, "NtGdiCloseProcess: illegal cutype\n");
|
|
|
|
//
|
|
// Enum all the objects for the process and kill them.
|
|
//
|
|
// For MultiUserGreCleanup, MultiUserGreCleanupHmgRemoveAllLocks is
|
|
// called for each object type to force all such objects in the
|
|
// handle manager to be unlocked and deletable.
|
|
//
|
|
|
|
//
|
|
// Cleanup DCs.
|
|
//
|
|
|
|
vCleanupDCs(W32Pid);
|
|
|
|
//
|
|
// Cleanup fonts.
|
|
//
|
|
|
|
if (cutype == CLEANUP_SESSION)
|
|
MultiUserGreCleanupHmgRemoveAllLocks((OBJTYPE)LFONT_TYPE);
|
|
else if (cutype == CLEANUP_PROCESS)
|
|
MultiUserGreCleanupHmgOwnRemoveAllLocks((OBJTYPE)LFONT_TYPE);
|
|
vCleanupFonts(W32Pid);
|
|
|
|
//
|
|
// Cleanup brushes.
|
|
//
|
|
|
|
if (cutype == CLEANUP_SESSION)
|
|
MultiUserGreCleanupHmgRemoveAllLocks((OBJTYPE)BRUSH_TYPE);
|
|
else if(cutype == CLEANUP_PROCESS)
|
|
MultiUserGreCleanupHmgOwnRemoveAllLocks((OBJTYPE)BRUSH_TYPE);
|
|
vCleanupBrushes(W32Pid);
|
|
|
|
//
|
|
// Clean up the ddraw & d3d types
|
|
//
|
|
|
|
DxDdCloseProcess(W32Pid);
|
|
|
|
//
|
|
// Cleanup surfaces.
|
|
//
|
|
|
|
if (cutype == CLEANUP_SESSION)
|
|
{
|
|
//
|
|
// Need to forget about some global/default objects so they
|
|
// can be deleted.
|
|
//
|
|
|
|
SURFACE::pdibDefault = NULL;
|
|
ppalDefault = NULL;
|
|
ppalMono = NULL;
|
|
hpalMono = (HPALETTE) 0;
|
|
|
|
MultiUserGreCleanupHmgRemoveAllLocks((OBJTYPE)SURF_TYPE);
|
|
}
|
|
else if (cutype == CLEANUP_PROCESS)
|
|
MultiUserGreCleanupHmgOwnRemoveAllLocks((OBJTYPE)SURF_TYPE);
|
|
|
|
vCleanupSurfaces(W32Pid, cutype);
|
|
|
|
//
|
|
// Cleanup regions.
|
|
//
|
|
|
|
if (cutype == CLEANUP_SESSION)
|
|
{
|
|
//
|
|
// Need to forget about some global/default objects so they
|
|
// can be deleted.
|
|
//
|
|
|
|
hrgnDefault = NULL;
|
|
prgnDefault = NULL;
|
|
|
|
MultiUserGreCleanupHmgRemoveAllLocks((OBJTYPE)RGN_TYPE);
|
|
}
|
|
else if (cutype == CLEANUP_PROCESS)
|
|
MultiUserGreCleanupHmgOwnRemoveAllLocks((OBJTYPE)RGN_TYPE);
|
|
|
|
vCleanupRegions(W32Pid);
|
|
|
|
//
|
|
// Cleanup ICM color spaces.
|
|
//
|
|
|
|
if (cutype == CLEANUP_SESSION)
|
|
{
|
|
//
|
|
// Need to forget about some global/default objects so they
|
|
// can be deleted.
|
|
//
|
|
|
|
ghStockColorSpace = NULL;
|
|
|
|
MultiUserGreCleanupHmgRemoveAllLocks((OBJTYPE)ICMLCS_TYPE);
|
|
}
|
|
else if (cutype == CLEANUP_PROCESS)
|
|
MultiUserGreCleanupHmgOwnRemoveAllLocks((OBJTYPE)ICMLCS_TYPE);
|
|
|
|
vCleanupLCSPs(W32Pid);
|
|
|
|
//
|
|
// Cleanup private fonts.
|
|
//
|
|
|
|
if (cutype == CLEANUP_SESSION)
|
|
{
|
|
//
|
|
// Relinquish locks on ALL remaining objects in handle manager.
|
|
//
|
|
|
|
MultiUserGreCleanupHmgRemoveAllLocks((OBJTYPE)DEF_TYPE);
|
|
}
|
|
else if (cutype == CLEANUP_PROCESS)
|
|
{
|
|
MultiUserGreCleanupHmgOwnRemoveAllLocks((OBJTYPE)DEF_TYPE);
|
|
}
|
|
|
|
if (cutype == CLEANUP_PROCESS)
|
|
{
|
|
// Private fonts should be cleaned up when a process goes away.
|
|
|
|
vCleanupPrivateFonts();
|
|
}
|
|
|
|
//
|
|
// Remove the ppalColor reference in the palettes
|
|
//
|
|
|
|
vRemoveRefPalettes(W32Pid);
|
|
|
|
|
|
// Clean up the rest
|
|
//
|
|
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, W32Pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, W32Pid))
|
|
{
|
|
switch (HmgObjtype(hobj))
|
|
{
|
|
case PAL_TYPE:
|
|
bRes = bDeletePalette((HPAL)hobj, TRUE, cutype);
|
|
break;
|
|
|
|
case EFSTATE_TYPE:
|
|
bRes = bEnumFontClose((ULONG_PTR)hobj);
|
|
break;
|
|
|
|
case DRVOBJ_TYPE:
|
|
{
|
|
HmgSetLock(hobj, 0);
|
|
|
|
//
|
|
// Free the DRIVEROBJ.
|
|
//
|
|
|
|
DRIVEROBJ *pdriv = EngLockDriverObj((HDRVOBJ)hobj);
|
|
|
|
PDEVOBJ po(pdriv->hdev);
|
|
|
|
ASSERTGDI(po.bValid(), "ERROR invalid PDEV in DRIVEROBJ");
|
|
|
|
BOOL bRet = EngDeleteDriverObj((HDRVOBJ)hobj, TRUE, TRUE);
|
|
|
|
ASSERTGDI(bRet, "Cleanup driver objects failed in process termination");
|
|
}
|
|
break;
|
|
|
|
case CLIENTOBJ_TYPE:
|
|
GreDeleteClientObj(hobj);
|
|
break;
|
|
|
|
default:
|
|
bRes = FALSE;
|
|
break;
|
|
}
|
|
|
|
#if DBG
|
|
if (bRes == FALSE)
|
|
{
|
|
//
|
|
// During shutdown, fonts are handled later so that public
|
|
// fonts and tables can be safely deleted (see function
|
|
// MultiUserGreCleanupAllFonts).
|
|
//
|
|
|
|
if ((cutype != CLEANUP_SESSION) ||
|
|
((HmgObjtype(hobj) != PFE_TYPE) &&
|
|
(HmgObjtype(hobj) != PFT_TYPE)))
|
|
{
|
|
DbgPrint("GDI ERROR: vCleanup couldn't delete "
|
|
"obj = %lx, type j=%lx\n", hobj, HmgObjtype(hobj));
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return bRes;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 24-Jul-1991 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C"
|
|
NTSTATUS
|
|
GdiProcessCallout(
|
|
IN PW32PROCESS Process,
|
|
IN BOOLEAN Initialize
|
|
)
|
|
{
|
|
|
|
BOOL bRes = TRUE;
|
|
|
|
if (Initialize)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PPEB Peb;
|
|
|
|
RtlInitializeGenericTableAvl(&Process->GDIEngUserMemAllocTable,
|
|
GDIEngUserMemAllocNodeCompare,
|
|
GDIEngUserMemAllocNodeAlloc,
|
|
GDIEngUserMemAllocNodeFree,
|
|
0);
|
|
|
|
InitializeListHead(&Process->GDIDcAttrFreeList);
|
|
InitializeListHead(&Process->GDIBrushAttrFreeList);
|
|
|
|
//
|
|
// check if the PEB is valid, if not then this is the SYSTEM process
|
|
// and has a NULL PEB. This process has no user-mode access so it
|
|
// is not neccessary to map in the shared handle table.
|
|
//
|
|
|
|
Peb = PsGetProcessPeb(Process->Process);
|
|
if (Peb != NULL)
|
|
{
|
|
//
|
|
// Temporary entry to allow setting GDI
|
|
// batch limit before each process startup.
|
|
//
|
|
|
|
Peb->GdiDCAttributeList = gInitialBatchCount;
|
|
|
|
ASSERTGDI(sizeof(Peb->GdiHandleBuffer) >= sizeof(GDIHANDLECACHE),
|
|
"Handle cache not large enough");
|
|
|
|
RtlZeroMemory(Peb->GdiHandleBuffer, sizeof(GDIHANDLECACHE));
|
|
|
|
//
|
|
// map a READ_ONLY view of the hmgr shared handle table into the
|
|
// process's address space
|
|
//
|
|
|
|
PVOID BaseAddress = NULL;
|
|
SIZE_T CommitSize = 0;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE SectionHandle = NULL;
|
|
|
|
ntStatus = ObOpenObjectByPointer( gpHmgrSharedHandleSection,
|
|
OBJ_KERNEL_HANDLE,
|
|
(PACCESS_STATE) NULL,
|
|
SECTION_ALL_ACCESS,
|
|
(POBJECT_TYPE) NULL,
|
|
KernelMode,
|
|
&SectionHandle);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0L,
|
|
0L,
|
|
NULL,
|
|
&CommitSize,
|
|
ViewUnmap,
|
|
0L,
|
|
PAGE_READONLY
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// set table address
|
|
//
|
|
// we must set the GdiSharedHandleTable value
|
|
// to the shared table pointer so that if GDI32 gets
|
|
// unloaded and re-loaded it can still get the pointer.
|
|
//
|
|
// NOTE: we also depend on this pointer being initialized
|
|
// *BEFORE* we make any GDI or USER call to the kernel
|
|
// (which has the automatic side-effect of calling this
|
|
// routine.
|
|
//
|
|
|
|
Peb->GdiSharedHandleTable =
|
|
(PVOID)BaseAddress;
|
|
}
|
|
else
|
|
{
|
|
KdPrint(("ZwMapViewOfSection fails, status = 0x%lx\n",ntStatus));
|
|
ntStatus = STATUS_DLL_INIT_FAILED;
|
|
}
|
|
|
|
ZwClose(SectionHandle);
|
|
}
|
|
else
|
|
{
|
|
KdPrint(("ObOpenObjectByPointer fails, status = 0x%lx\n",ntStatus));
|
|
ntStatus = STATUS_DLL_INIT_FAILED;
|
|
}
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This call takes place when the last thread of a process goes away.
|
|
// Note that such thread might not be a w32 thread
|
|
//
|
|
|
|
//
|
|
// first lets see if this is the spooler and if so, clean him up
|
|
vCleanupSpool();
|
|
|
|
W32PID W32Pid = W32GetCurrentPID();
|
|
|
|
bRes = NtGdiCloseProcess(W32Pid, CLEANUP_PROCESS);
|
|
|
|
if (bRes)
|
|
{
|
|
if(Process->GDIHandleCount != 0)
|
|
{
|
|
WARNING("GdiProcessCallout: handle count != 0 at termination\n");
|
|
}
|
|
|
|
}
|
|
|
|
if (Process)
|
|
{
|
|
PGDIENGUSERMEMALLOCNODE pNode;
|
|
PVOID Restart = NULL;
|
|
|
|
for (pNode = (PGDIENGUSERMEMALLOCNODE)RtlEnumerateGenericTableAvl(&Process->GDIEngUserMemAllocTable,TRUE);
|
|
pNode;
|
|
pNode = (PGDIENGUSERMEMALLOCNODE)RtlEnumerateGenericTableAvl(&Process->GDIEngUserMemAllocTable,FALSE))
|
|
{
|
|
RtlDeleteElementGenericTableAvl(&Process->GDIEngUserMemAllocTable,pNode);
|
|
}
|
|
|
|
PLIST_ENTRY ListHead = &Process->GDIDcAttrFreeList;
|
|
PLIST_ENTRY NextEntry = ListHead->Flink;
|
|
|
|
// Note in these loops we check for non NULL NextEntry also.
|
|
// Why? Sometimes it seems GDIProcessCallout is called for
|
|
// process termination even though it was not called for
|
|
// initialization. If this is the case then the NextEntry will
|
|
// be NULL instead of pointing to List Anchor. Hence to handle
|
|
// this we do this extra check.
|
|
|
|
if (NextEntry)
|
|
{
|
|
while (NextEntry != ListHead)
|
|
{
|
|
PLIST_ENTRY pFree = NextEntry;
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
VFREEMEM(pFree);
|
|
}
|
|
}
|
|
|
|
ListHead = &Process->GDIBrushAttrFreeList;
|
|
NextEntry = ListHead->Flink;
|
|
|
|
if (NextEntry)
|
|
{
|
|
while (NextEntry != ListHead)
|
|
{
|
|
PLIST_ENTRY pFree = NextEntry;
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
VFREEMEM(pFree);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (bRes ? STATUS_SUCCESS : STATUS_CANNOT_DELETE);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GdiThreadCallout
|
|
*
|
|
* For Inintialize case, set initial values for W32THREAD elements.
|
|
* For rundown case, move all thread DCATTR memory blocks to the process
|
|
* list.
|
|
*
|
|
* History:
|
|
*
|
|
* 15-May-1995 -by- Mark Enstrom [marke]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
extern "C"
|
|
VOID GdiThreadCallout(
|
|
IN PETHREAD pEThread,
|
|
IN PSW32THREADCALLOUTTYPE CalloutType
|
|
)
|
|
{
|
|
|
|
switch (CalloutType)
|
|
{
|
|
case PsW32ThreadCalloutInitialize:
|
|
{
|
|
PW32THREAD pThread;
|
|
pThread = (PW32THREAD) PsGetThreadWin32Thread(pEThread);
|
|
|
|
InitializeListHead(&pThread->GdiTmpAllocList);
|
|
break;
|
|
}
|
|
case PsW32ThreadCalloutExit:
|
|
{
|
|
PDC_ATTR pdca;
|
|
PW32THREAD pThread;
|
|
|
|
//
|
|
// Flush the TEB batch. KiSystemService flushes the batch
|
|
// only if the service is a win32k.sys service. During thread
|
|
// termination, the transition to kernel mode is not one of
|
|
// these, and so we can get here without the batch being
|
|
// flushed. Bug #338052 demonstrated this.
|
|
//
|
|
|
|
GdiThreadCalloutFlushUserBatch();
|
|
|
|
//
|
|
// W32 thread execution end. Note that the thread
|
|
// object can be locked so it might be used after
|
|
// this call returns.
|
|
//
|
|
|
|
pdca = (PDC_ATTR)((PW32THREAD)PsGetThreadWin32Thread(pEThread))->pgdiDcattr;
|
|
if (pdca != NULL)
|
|
{
|
|
|
|
//
|
|
// Thread->pgdiDcattr is not NULL so HmgFreeDcAttr will
|
|
// not put pdca back on thread but will place it on the
|
|
// process list.
|
|
//
|
|
|
|
HmgFreeDcAttr(pdca);
|
|
}
|
|
|
|
#if !defined(_GDIPLUS_)
|
|
|
|
//
|
|
// Clean up user mode printer driver related stuff
|
|
//
|
|
|
|
pThread = (PW32THREAD) PsGetThreadWin32Thread(pEThread);
|
|
|
|
{
|
|
PUMPDOBJ pumpdobj;
|
|
|
|
while (pumpdobj = (PUMPDOBJ)pThread->pUMPDObjs)
|
|
{
|
|
pumpdobj->Cleanup();
|
|
VFREEMEM(pumpdobj);
|
|
}
|
|
}
|
|
|
|
if (pThread->pUMPDHeap != NULL)
|
|
DestroyUMPDHeap((PUMPDHEAP) pThread->pUMPDHeap);
|
|
|
|
#if defined(_WIN64)
|
|
//
|
|
// Cleanup Proxy port
|
|
//
|
|
|
|
if(pThread->pProxyPort)
|
|
{
|
|
PROXYPORT proxyport((ProxyPort*)pThread->pProxyPort);
|
|
|
|
proxyport.Close();
|
|
pThread->pProxyPort = NULL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef VALIDATE_LOCKS
|
|
//
|
|
// Cleanup any debug block that may have been allocated
|
|
//
|
|
|
|
if(pThread->pSemTable)
|
|
{
|
|
VFREEMEM(pThread->pSemTable);
|
|
pThread->pSemTable = NULL;
|
|
}
|
|
#endif
|
|
|
|
// Cleanup per thread Tmp Allocations
|
|
{
|
|
PLIST_ENTRY ListHead = &pThread->GdiTmpAllocList;
|
|
PLIST_ENTRY NextEntry = ListHead->Flink;
|
|
|
|
while(NextEntry != ListHead)
|
|
{
|
|
PLIST_ENTRY pFree = NextEntry;
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
VFREEMEM(pFree);
|
|
}
|
|
}
|
|
#endif // !_GDIPLUS_
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|