/****************************** 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); } }