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.
457 lines
14 KiB
457 lines
14 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: cleanup.c
|
|
*
|
|
* Copyright (c) 1985-95, Microsoft Corporation
|
|
*
|
|
* This module contains code used to clean up after a dying thread.
|
|
*
|
|
* History:
|
|
* 02-15-91 DarrinM Created.
|
|
* 01-16-92 IanJa Neutralized ANSI/UNICODE (debug strings kept ANSI)
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
extern CONST BYTE gabObjectCreateFlags[];
|
|
|
|
/***************************************************************************\
|
|
* CheckForClientDeath
|
|
*
|
|
* Check to see if the client thread that is paired to the current running
|
|
* server thread has died. If it has, we raise an exception so this thread
|
|
* can perform its cleanup duties. NOTE: If the client has died, this
|
|
* will not be returning back to its caller.
|
|
*
|
|
* History:
|
|
* 05-23-91 DarrinM Created.
|
|
\***************************************************************************/
|
|
|
|
VOID ClientDied(VOID)
|
|
{
|
|
|
|
/*
|
|
* Raise an exception to force cleanup.
|
|
*/
|
|
ExRaiseStatus( STATUS_PORT_DISCONNECTED );
|
|
}
|
|
|
|
|
|
/*
|
|
* Determines if a Wow wndproc is in a selector list
|
|
*/
|
|
BOOL
|
|
WowWndProcInSelList(
|
|
WNDPROC_PWND lpfnWndProc,
|
|
PWORD SelList
|
|
)
|
|
{
|
|
WORD wWndProcSel = HIWORD(lpfnWndProc);
|
|
WORD nsel = *SelList++;
|
|
|
|
while (nsel--) {
|
|
if (wWndProcSel == *SelList++) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* PseudoDestroyClassWindows
|
|
*
|
|
* Walk the window tree from hwndParent looking for windows
|
|
* of class wndClass. If one is found, destroy it.
|
|
*
|
|
*
|
|
* WARNING windows actually destroys these windows. We only zombie-ize them
|
|
* so this call does not have to be an xxx call.
|
|
*
|
|
* History:
|
|
* 25-Mar-1994 JohnC from win 3.1
|
|
\***************************************************************************/
|
|
|
|
VOID PseudoDestroyClassWindows(PWND pwndParent, PCLS pcls)
|
|
{
|
|
PWND pwnd;
|
|
PTHREADINFO pti;
|
|
|
|
pti = PtiCurrent();
|
|
|
|
/*
|
|
* Recursively walk the window list and zombie any windows of this class
|
|
*/
|
|
for (pwnd = pwndParent->spwndChild; pwnd != NULL; pwnd = pwnd->spwndNext) {
|
|
|
|
/*
|
|
* If this window belongs to this class then zombie it
|
|
* if it was created by this message thread.
|
|
*/
|
|
if (pwnd->pcls == pcls && pti == GETPTI(pwnd)) {
|
|
|
|
/*
|
|
* Zombie-ize the window
|
|
*
|
|
* Remove references to the client side window proc because that
|
|
* WOW selector has been freed.
|
|
*/
|
|
|
|
RIPMSG1(RIP_WARNING,
|
|
"USER: Wow Window not destroyed: %lX", pwnd);
|
|
|
|
if (!TestWF(pwnd, WFSERVERSIDEPROC)) {
|
|
pwnd->lpfnWndProc = (WNDPROC_PWND)gpsi->apfnClientA.pfnDefWindowProc;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recurse downward to look for any children that might be
|
|
* of this class.
|
|
*/
|
|
if (pwnd->spwndChild != NULL)
|
|
PseudoDestroyClassWindows(pwnd, pcls);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Determines if a selector is in a selector list
|
|
*/
|
|
BOOL SelectorInSelList(
|
|
PNEMODULESEG SelList,
|
|
DWORD nSel,
|
|
USHORT sel)
|
|
{
|
|
int nInd;
|
|
|
|
for (nInd = 0; nInd < (int)nSel; nInd++) {
|
|
if (SelList->ns_handle + 1 == sel) {
|
|
return TRUE;
|
|
}
|
|
SelList++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* Go through all the windows owned by the dying queue and do the following:
|
|
*
|
|
* 1. Restore Standard window classes have their window procs restored
|
|
* to their original value, in case they were subclassed.
|
|
*
|
|
* 2. App window classes have their window procs set to DefWindowProc
|
|
* so that we don't execute any app code.
|
|
*
|
|
* Array of original window proc addresses,
|
|
* indexed by ICLS_* value.
|
|
\***************************************************************************/
|
|
|
|
static PROC spfnwp[] =
|
|
{
|
|
0, // ICLS_BUTTON
|
|
0, // ICLS_EDIT: SPECIAL CASE!
|
|
0, // ICLS_STATIC
|
|
0, // ICLS_LISTBOX
|
|
0, // ICLS_SCROLLBAR
|
|
0, // ICLS_COMBOBOX
|
|
0, // ICLS_DESKTOP
|
|
0, // ICLS_DIALOG
|
|
0, // ICLS_MENU
|
|
0, // ICLS_SWITCH
|
|
0, // ICLS_ICONTITLE
|
|
0, // ICLS_MDICLIENT
|
|
0 // ICLS_COMBOLISTBOX
|
|
};
|
|
|
|
/***************************************************************************\
|
|
* _WOWCleanup
|
|
*
|
|
* Private API to allow WOW to cleanup any process-owned resources when
|
|
* a WOW thread exits or when a DLL is unloaded.
|
|
*
|
|
* Note that at module cleanup, hInstance = the module handle and hTaskWow
|
|
* is NULL. On task cleanup, hInstance = the hInst/hTask combined which
|
|
* matches the value passed in hModule to WowServerCreateCursorIcon and
|
|
* hTaskWow != NULL.
|
|
*
|
|
* History:
|
|
* 09-02-92 JimA Created.
|
|
\***************************************************************************/
|
|
|
|
VOID _WOWCleanup(
|
|
HANDLE hInstance,
|
|
DWORD hTaskWow,
|
|
PNEMODULESEG SelList,
|
|
DWORD nSel)
|
|
{
|
|
PNEMODULESEG SelListOrg = SelList;
|
|
PPROCESSINFO ppi = PpiCurrent();
|
|
PPCLS ppcls;
|
|
PHE pheT, pheMax;
|
|
int i;
|
|
DWORD cbSel, nSelOrg = nSel;
|
|
PWORD SelListTemp;
|
|
PWORD pw;
|
|
static BOOL sbFirstCall = TRUE;
|
|
|
|
if (sbFirstCall) {
|
|
spfnwp[0] = gpsi->apfnClientW.pfnButtonWndProc;
|
|
spfnwp[1] = gpsi->apfnClientW.pfnDefWindowProc;
|
|
spfnwp[2] = gpsi->apfnClientW.pfnStaticWndProc;
|
|
spfnwp[3] = gpsi->apfnClientW.pfnListBoxWndProc;
|
|
spfnwp[4] = xxxSBWndProc;
|
|
spfnwp[5] = gpsi->apfnClientW.pfnComboBoxWndProc;
|
|
spfnwp[6] = xxxDesktopWndProc;
|
|
spfnwp[7] = gpsi->apfnClientW.pfnDialogWndProc;
|
|
spfnwp[8] = xxxMenuWindowProc;
|
|
spfnwp[9] = xxxSwitchWndProc;
|
|
spfnwp[10] = gpsi->apfnClientW.pfnTitleWndProc;
|
|
spfnwp[11] = gpsi->apfnClientW.pfnMDIClientWndProc;
|
|
spfnwp[12] = gpsi->apfnClientW.pfnComboListBoxProc;
|
|
|
|
sbFirstCall = FALSE;
|
|
}
|
|
|
|
/*
|
|
* PseudoDestroy windows with wndprocs from this hModule
|
|
* If its a wow16 wndproc, search the selector list by wndproc sel
|
|
* and Nuke matches. We assume that ONLY 16bit wndprocs have the
|
|
* hi-bit set. and that all other WndProcs are uninteresting.
|
|
*/
|
|
SelListTemp = NULL;
|
|
if (nSel) {
|
|
cbSel = (nSel + 1) * sizeof(WORD);
|
|
SelListTemp = UserAllocPoolWithQuota(cbSel, TAG_WOW);
|
|
if (SelListTemp == NULL)
|
|
return;
|
|
try {
|
|
#if defined(_X86_)
|
|
ProbeForRead(SelList, nSel * sizeof(*SelList), sizeof(BYTE));
|
|
#else
|
|
ProbeForRead(SelList, nSel * sizeof(*SelList), sizeof(WORD));
|
|
#endif
|
|
*(LPWORD)SelListTemp = (WORD)nSel;
|
|
pw = (LPWORD)SelListTemp + 1;
|
|
while (nSel--) {
|
|
*pw = SelList->ns_handle | 1;
|
|
//
|
|
// transform into a "Wow WndProc sel"
|
|
// set hi-bit, but if hibit already set clear LDT bit
|
|
//
|
|
if (*pw & HIWORD(WNDPROC_WOW)) {
|
|
*pw &= ~0x0004;
|
|
}
|
|
else {
|
|
*pw |= HIWORD(WNDPROC_WOW);
|
|
}
|
|
|
|
pw++;
|
|
SelList++;
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
RIPMSG1(RIP_ERROR, "Exception %x", GetExceptionCode());
|
|
UserFreePool(SelListTemp);
|
|
return;
|
|
}
|
|
|
|
if (*(LPWORD)SelListTemp) {
|
|
pheMax = &gSharedInfo.aheList[giheLast];
|
|
for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
|
|
|
|
if (pheT->bType == TYPE_WINDOW) {
|
|
PWND pwnd = (PWND) pheT->phead;
|
|
|
|
if ((WNDPROC_WOW & (ULONG)pwnd->lpfnWndProc) &&
|
|
((PTHREADINFO)pheT->pOwner)->ppi == ppi &&
|
|
WowWndProcInSelList(pwnd->lpfnWndProc, SelListTemp))
|
|
{
|
|
RIPMSG1(RIP_WARNING,
|
|
"USER: Wow Window not destroyed: %lX", pwnd);
|
|
pwnd->lpfnWndProc = (WNDPROC_PWND)gpsi->apfnClientA.pfnDefWindowProc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UserFreePool(SelListTemp);
|
|
}
|
|
|
|
/*
|
|
* If hInstance is specified, a DLL is being unloaded. If any
|
|
* classes were registered by the DLL and there are still windows
|
|
* around that reference these classes, keep the classes until
|
|
* the WOW thread exits.
|
|
*/
|
|
if (hTaskWow == 0) {
|
|
|
|
/*
|
|
* Module cleanup
|
|
*/
|
|
|
|
/*
|
|
* Destroy private classes identified by hInstance that are not
|
|
* referenced by any windows. Mark in-use classes for later
|
|
* destruction.
|
|
*/
|
|
ppcls = &(ppi->pclsPrivateList);
|
|
|
|
for (i = 0; i < 2; ++i) {
|
|
while (*ppcls != NULL) {
|
|
|
|
USHORT sel;
|
|
|
|
if (HIWORD((*ppcls)->hModule) == (WORD)hInstance) {
|
|
if ((*ppcls)->cWndReferenceCount == 0) {
|
|
DestroyClass(ppcls);
|
|
/*
|
|
* DestroyClass does *ppcls = pcls->pclsNext;
|
|
* so we just want continue here
|
|
*/
|
|
} else {
|
|
|
|
/*
|
|
* Zap all the windows around that belong to this class.
|
|
*/
|
|
PseudoDestroyClassWindows(PtiCurrent()->rpdesk->pDeskInfo->spwnd, *ppcls);
|
|
|
|
/*
|
|
* Win 3.1 does not distinguish between Dll's and Exe's
|
|
*/
|
|
(*ppcls)->flags |= CSF_WOWDEFERDESTROY;
|
|
ppcls = &((*ppcls)->pclsNext);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
sel = HIWORD((*ppcls)->adwWOW[0]);
|
|
|
|
if (SelectorInSelList(SelListOrg, nSelOrg, sel)) {
|
|
ATOM atom;
|
|
int iSel;
|
|
|
|
(*ppcls)->adwWOW[0] = 0;
|
|
|
|
/*
|
|
* See if the window's class atom matches any of
|
|
* the system ones. If so, jam in the original window proc.
|
|
* Otherwise, use DefWindowProc
|
|
*/
|
|
atom = (*ppcls)->atomClassName;
|
|
for (iSel = 0; iSel < sizeof(spfnwp); iSel++) {
|
|
if (atom == gpsi->atomSysClass[iSel]) {
|
|
(*ppcls)->lpfnWndProc = (WNDPROC_PWND)spfnwp[iSel];
|
|
break;
|
|
}
|
|
}
|
|
if (iSel == sizeof(spfnwp))
|
|
(*ppcls)->lpfnWndProc = (WNDPROC_PWND)gpsi->apfnClientW.pfnDefWindowProc;
|
|
}
|
|
|
|
ppcls = &((*ppcls)->pclsNext);
|
|
}
|
|
|
|
/*
|
|
* Destroy public classes identified by hInstance that are not
|
|
* referenced by any windows. Mark in-use classes for later
|
|
* destruction.
|
|
*/
|
|
ppcls = &(ppi->pclsPublicList);
|
|
}
|
|
return;
|
|
|
|
} else if (hInstance != NULL) {
|
|
|
|
/*
|
|
* Task cleanup
|
|
*/
|
|
|
|
PWND pwnd;
|
|
hTaskWow = (DWORD) LOWORD(hTaskWow);
|
|
/*
|
|
* Task exit called by wow. This loop will Pseudo-Destroy windows
|
|
* created by this task.
|
|
*/
|
|
pheMax = &gSharedInfo.aheList[giheLast];
|
|
for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
|
|
PTHREADINFO ptiTest = (PTHREADINFO)pheT->pOwner;
|
|
if ((pheT->bType == TYPE_WINDOW) &&
|
|
(ptiTest->TIF_flags & TIF_16BIT) &&
|
|
(ptiTest->ptdb) &&
|
|
(ptiTest->ptdb->hTaskWow == hTaskWow) &&
|
|
(ptiTest->ppi == ppi)) {
|
|
|
|
pwnd = (PWND) pheT->phead;
|
|
if (!TestWF(pwnd, WFSERVERSIDEPROC)) {
|
|
pwnd->lpfnWndProc = (WNDPROC_PWND)gpsi->apfnClientA.pfnDefWindowProc;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If we get here, we are in thread cleanup and all of the thread's windows
|
|
* have been destroyed or disassociated with any classes. If a class
|
|
* marked for destruction at this point still has windows, they must
|
|
* belong to a dll.
|
|
*/
|
|
|
|
/*
|
|
* Destroy private classes marked for destruction
|
|
*/
|
|
ppcls = &(ppi->pclsPrivateList);
|
|
for (i = 0; i < 2; ++i) {
|
|
while (*ppcls != NULL) {
|
|
if ((*ppcls)->hTaskWow == hTaskWow &&
|
|
((*ppcls)->flags & CSF_WOWDEFERDESTROY)) {
|
|
if ((*ppcls)->cWndReferenceCount == 0) {
|
|
DestroyClass(ppcls);
|
|
} else {
|
|
RIPMSG0(RIP_ERROR, "Windows remain for a WOW class marked for destruction");
|
|
ppcls = &((*ppcls)->pclsNext);
|
|
}
|
|
} else
|
|
ppcls = &((*ppcls)->pclsNext);
|
|
}
|
|
|
|
/*
|
|
* Destroy public classes marked for destruction
|
|
*/
|
|
ppcls = &(ppi->pclsPublicList);
|
|
}
|
|
|
|
/*
|
|
* Destroy menus, cursors, icons and accel tables identified by hTaskWow
|
|
*/
|
|
pheMax = &gSharedInfo.aheList[giheLast];
|
|
for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
|
|
|
|
/*
|
|
* Check against free before we look at ppi... because pq is stored
|
|
* in the object itself, which won't be there if TYPE_FREE.
|
|
*/
|
|
if (pheT->bType == TYPE_FREE)
|
|
continue;
|
|
|
|
/*
|
|
* Destroy those objects created by this task.
|
|
*/
|
|
if (!(gabObjectCreateFlags[pheT->bType] & OCF_PROCESSOWNED) ||
|
|
(PPROCESSINFO)pheT->pOwner != ppi ||
|
|
((PPROCOBJHEAD)pheT->phead)->hTaskWow != hTaskWow)
|
|
continue;
|
|
|
|
/*
|
|
* Make sure this object isn't already marked to be destroyed - we'll
|
|
* do no good if we try to destroy it now since it is locked.
|
|
*/
|
|
if (pheT->bFlags & HANDLEF_DESTROY) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Destroy this object.
|
|
*/
|
|
HMDestroyUnlockedObject(pheT);
|
|
}
|
|
}
|