2025-04-27 07:49:33 -04:00

331 lines
11 KiB
C

/****************************** Module Header ******************************\
* Module Name: cleanup.c
*
* Copyright (c) 1985 - 1999, 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
/***************************************************************************\
* 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.
\***************************************************************************/
/***************************************************************************\
* 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);
}
}
/***************************************************************************\
* 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 is in globals.c now -- gpfnwp.
*
* This array is initialized in code in init.c.
\***************************************************************************/
VOID _WOWModuleUnload(HANDLE hModule) {
PPROCESSINFO ppi = PpiCurrent();
PHE pheT, pheMax;
PPCLS ppcls;
int i;
UserAssert(gpfnwp[0]);
/*
* PseudoDestroy windows with wndprocs from this hModule
* If its a wow16 wndproc, check if the hMod16 is this module
* and Nuke matches.
*/
pheMax = &gSharedInfo.aheList[giheLast];
for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
PTHREADINFO ptiTest = (PTHREADINFO)pheT->pOwner;
PWND pwnd;
if ((pheT->bType == TYPE_WINDOW) &&
(ptiTest->TIF_flags & TIF_16BIT) &&
(ptiTest->ppi == ppi)) {
pwnd = (PWND) pheT->phead;
if (!TestWF(pwnd, WFSERVERSIDEPROC) &&
IsWOWProc(pwnd->lpfnWndProc) &&
(pwnd->hMod16 == (WORD)(ULONG_PTR)hModule)) {
pwnd->lpfnWndProc = (WNDPROC_PWND)gpsi->apfnClientA.pfnDefWindowProc;
}
}
}
/*
* 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) {
PWC pwc;
PCLS pcls;
if (HIWORD((ULONG_PTR)(*ppcls)->hModule) == (WORD)(ULONG_PTR)hModule) {
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)->CSF_flags |= CSF_WOWDEFERDESTROY;
ppcls = &((*ppcls)->pclsNext);
}
continue;
}
pcls = *ppcls;
if ((pcls->CSF_flags & CSF_WOWCLASS) && ((WORD)(ULONG_PTR)hModule == (pwc = PWCFromPCLS(pcls))->hMod16)) {
ATOM atom;
int iSel;
/*
* 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 = ICLS_BUTTON; iSel < ICLS_MAX; iSel++) {
if ((gpfnwp[iSel]) && (atom == gpsi->atomSysClass[iSel])) {
(*ppcls)->lpfnWndProc = (WNDPROC_PWND)gpfnwp[iSel];
break;
}
}
if (iSel == ICLS_MAX)
(*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;
}
/***************************************************************************\
* _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)
{
PPROCESSINFO ppi = PpiCurrent();
PPCLS ppcls;
PHE pheT, pheMax;
int i;
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)->CSF_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 ( !(gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) ||
(PPROCESSINFO)pheT->pOwner != ppi ||
(((PPROCOBJHEAD)pheT->phead)->hTaskWow != hTaskWow) ||
(pheT->bType == TYPE_CALLPROC) /* Do not destroy CALLPROCDATA objects.
* These should only get nuked when the
* process goes away or when the class
* is nuked.
*/
) {
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);
}
}