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.
312 lines
10 KiB
312 lines
10 KiB
/****************************** 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
|
|
|
|
/***************************************************************************\
|
|
* 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: 0x%p", 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* _WOWModuleUnload
|
|
*
|
|
* 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 to continue here.
|
|
*/
|
|
} else {
|
|
/*
|
|
* Zap all the windows around that belong to this class.
|
|
*/
|
|
PseudoDestroyClassWindows(PtiCurrent()->rpdesk->pDeskInfo->spwnd, *ppcls);
|
|
|
|
(*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);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* _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) {
|
|
PWND pwnd;
|
|
|
|
/*
|
|
* Task cleanup.
|
|
*/
|
|
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.
|
|
*
|
|
* Do not destroy CALLPROCDATA objects. These should only get nuked
|
|
* when the process goes away or when the class is nuked.
|
|
*/
|
|
if (!(gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) ||
|
|
(PPROCESSINFO)pheT->pOwner != ppi ||
|
|
((PPROCOBJHEAD)pheT->phead)->hTaskWow != hTaskWow ||
|
|
pheT->bType == TYPE_CALLPROC) {
|
|
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);
|
|
}
|
|
}
|