mirror of https://github.com/lianthony/NT4.0
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.
573 lines
16 KiB
573 lines
16 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 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
extern BOOL bDeleteBrush(HBRUSH,BOOL);
|
|
|
|
|
|
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)
|
|
{
|
|
HOBJ hobj = HmgNextOwned((HOBJ) 0, pid);
|
|
|
|
for (;(hobj != (HOBJ) NULL);hobj = HmgNextOwned(hobj, pid))
|
|
{
|
|
if (HmgObjtype(hobj) == SURF_TYPE)
|
|
{
|
|
bDeleteSurface((HSURF)hobj);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************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******************************\
|
|
*
|
|
* 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)ro.prgn->pEntry;
|
|
|
|
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:
|
|
* 07-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bEnumFontClose(ULONG 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******************************\
|
|
*
|
|
* 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;
|
|
PPID_HANDLE_TRACK pHandleTrack = &Process->pidHandleTrack;
|
|
|
|
pHandleTrack->pNext = NULL;
|
|
pHandleTrack->pPrev = NULL;
|
|
|
|
Process->pDCAttrList = NULL;
|
|
Process->pBrushAttrList = NULL;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
if (Process->Process->Peb != NULL)
|
|
{
|
|
//
|
|
// BUGBUG Temporary entry to allow setting GDI
|
|
// batch limit before each process startup.
|
|
//
|
|
|
|
Process->Process->Peb->GdiDCAttributeList = (PVOID)gInitialBatchCount;
|
|
|
|
//
|
|
// zero handle table (assert size is enough!!!)
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
Process->Process->Peb->GdiHandleBuffer,
|
|
sizeof(GDIHANDLECACHE)
|
|
);
|
|
|
|
//
|
|
// map a READ_ONLY view of the hmgr shared handle table into the
|
|
// process's address space
|
|
//
|
|
|
|
PVOID BaseAddress = NULL;
|
|
ULONG CommitSize = 0;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE SectionHandle = NULL;
|
|
|
|
ntStatus = ObOpenObjectByPointer( gpHmgrSharedHandleSection,
|
|
0L,
|
|
(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.
|
|
//
|
|
|
|
Process->Process->Peb->GdiSharedHandleTable =
|
|
(PVOID)BaseAddress;
|
|
}
|
|
else
|
|
{
|
|
KdPrint(("ZwMapViewOfSection fails, status = 0x%lx\n",ntStatus));
|
|
ntStatus = STATUS_DLL_INIT_FAILED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KdPrint(("ObOpenObjectByPointer fails, status = 0x%lx\n",ntStatus));
|
|
ntStatus = STATUS_DLL_INIT_FAILED;
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
//
|
|
// add entry to global handle count track
|
|
//
|
|
|
|
{
|
|
//
|
|
// Add W32Process to GDI global linked list of active
|
|
// w32processes.
|
|
// Must be interlocked to add,delete and search list
|
|
//
|
|
|
|
ASSERTGDI(gpPidHandleList != NULL,"gpPidHandleList is NULL\n");
|
|
ASSERTGDI(gpPidHandleList->pNext != NULL,"gpPidHandleList->pNext is NULL\n");
|
|
ASSERTGDI(gpPidHandleList->pPrev != NULL,"gpPidHandleList->pPrev is NULL\n");
|
|
|
|
//
|
|
// init handle track and w32process, add handle track to linked list
|
|
//
|
|
|
|
PPID_HANDLE_TRACK pHandleTrack = &Process->pidHandleTrack;
|
|
|
|
pHandleTrack->HandleCount = 0;
|
|
pHandleTrack->Pid = (ULONG)W32GetCurrentPID();
|
|
|
|
//
|
|
// init into global list, list has sentinell
|
|
//
|
|
|
|
AcquireHmgrResource();
|
|
|
|
//
|
|
// insert into double linked list, just after
|
|
// sentinell
|
|
//
|
|
|
|
pHandleTrack->pNext = gpPidHandleList->pNext;
|
|
pHandleTrack->pPrev = gpPidHandleList;
|
|
gpPidHandleList->pNext->pPrev = pHandleTrack;
|
|
gpPidHandleList->pNext = pHandleTrack;
|
|
|
|
ReleaseHmgrResource();
|
|
}
|
|
}
|
|
|
|
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();
|
|
|
|
//
|
|
// Enum all the objects for the process and kill them.
|
|
//
|
|
vCleanupDCs(W32Pid);
|
|
vCleanupFonts(W32Pid);
|
|
vCleanupBrushes(W32Pid);
|
|
vCleanupSurfaces(W32Pid);
|
|
vCleanupRegions(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);
|
|
break;
|
|
|
|
case EFSTATE_TYPE:
|
|
bRes = bEnumFontClose((ULONG)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");
|
|
|
|
//
|
|
// Lock the screen semaphore so that no other calls are
|
|
// sent to the driver while the cleanup occurs.
|
|
//
|
|
|
|
VACQUIREDEVLOCK(po.pDevLock());
|
|
|
|
#if DBG
|
|
BOOL bRet =
|
|
#endif
|
|
|
|
EngDeleteDriverObj((HDRVOBJ)hobj, TRUE, TRUE);
|
|
|
|
ASSERTGDI(bRet, "Cleanup driver objects failed in process termination");
|
|
|
|
VRELEASEDEVLOCK(po.pDevLock());
|
|
}
|
|
break;
|
|
|
|
case CLIENTOBJ_TYPE:
|
|
GreDeleteClientObj(hobj);
|
|
break;
|
|
|
|
case DD_DIRECTDRAW_TYPE:
|
|
bRes = bDdDeleteDirectDrawObject((HANDLE)hobj, TRUE);
|
|
break;
|
|
|
|
case DD_SURFACE_TYPE:
|
|
bRes = bDdDeleteSurfaceObject((HANDLE)hobj, TRUE, NULL);
|
|
break;
|
|
|
|
default:
|
|
bRes = FALSE;
|
|
break;
|
|
}
|
|
|
|
#if DBG
|
|
if (bRes == FALSE)
|
|
{
|
|
DbgPrint("GDI ERROR: vCleanup couldn't delete obj = %lx, type j=%lx\n",
|
|
hobj, HmgObjtype(hobj));
|
|
//DbgBreakPoint();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (bRes)
|
|
{
|
|
//
|
|
// must synchronize removing W32PROCESS from global list
|
|
//
|
|
|
|
PPID_HANDLE_TRACK pHandleTrack = &Process->pidHandleTrack;
|
|
|
|
//
|
|
// validate handle track count and free
|
|
//
|
|
|
|
if (pHandleTrack->HandleCount != 0)
|
|
{
|
|
WARNING("GdiProcessCallout: handle count != 0 at termination\n");
|
|
}
|
|
|
|
//
|
|
// remove from list, list has sentinell
|
|
//
|
|
|
|
AcquireHmgrResource();
|
|
|
|
if (pHandleTrack->pNext != NULL)
|
|
{
|
|
pHandleTrack->pNext->pPrev = pHandleTrack->pPrev;
|
|
}
|
|
|
|
if (pHandleTrack->pPrev != NULL)
|
|
{
|
|
pHandleTrack->pPrev->pNext = pHandleTrack->pNext;
|
|
}
|
|
|
|
//
|
|
// safegaurd
|
|
//
|
|
|
|
pHandleTrack->pNext = NULL;
|
|
pHandleTrack->pPrev = NULL;
|
|
|
|
ReleaseHmgrResource();
|
|
}
|
|
}
|
|
|
|
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"
|
|
NTSTATUS
|
|
GdiThreadCallout(
|
|
IN PW32THREAD Thread,
|
|
IN PSW32THREADCALLOUTTYPE CalloutType
|
|
)
|
|
{
|
|
|
|
switch (CalloutType)
|
|
{
|
|
case PsW32ThreadCalloutInitialize:
|
|
Thread->pgdiDcattr = NULL;
|
|
Thread->pgdiBrushAttr = NULL;
|
|
break;
|
|
|
|
case PsW32ThreadCalloutExit:
|
|
{
|
|
//
|
|
// W32 thread execution end. Note that the thread
|
|
// object can be locked so it might be used after
|
|
// this call returns.
|
|
//
|
|
PW32PROCESS Process = W32GetCurrentProcess();
|
|
BOOL bStatus = FALSE;
|
|
NTSTATUS NtStatus;
|
|
|
|
//
|
|
// place any dcattr on the process list
|
|
//
|
|
|
|
if (Thread->pgdiDcattr != NULL)
|
|
{
|
|
|
|
PDC_ATTR pdca;
|
|
|
|
if (Thread->pgdiDcattr != NULL)
|
|
{
|
|
//
|
|
// get dc_attr from thread
|
|
//
|
|
|
|
pdca = (PDC_ATTR)Thread->pgdiDcattr;
|
|
|
|
//
|
|
// Thread->pgdiDcattr is not NULL so HmgFreeDcAttr will
|
|
// not put pdca back on thread but will place it on the
|
|
// process list.
|
|
//
|
|
|
|
HmgFreeDcAttr(pdca);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case PsW32ThreadCalloutDelete:
|
|
//
|
|
// Thread object has been completely unlocked. Do final clean up here.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this is changed so this function might return an error, W32pThreadCallout
|
|
// must be fixed in w32\kmode\w32init.c
|
|
//
|
|
return(STATUS_SUCCESS);
|
|
}
|