Leaked source code of windows server 2003
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.
 
 
 
 
 
 

550 lines
15 KiB

/****************************** Module Header ******************************\
* Module Name: enumwin.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Contains the EnumWindows API, BuildHwndList and related functions.
*
* History:
* 10-20-90 darrinm Created.
* ??-??-?? ianja Added Revalidation code
* 02-19-91 JimA Added enum access checks
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
PBWL pbwlCache;
#if DBG
PBWL pbwlCachePrev;
#endif
PBWL InternalBuildHwndList(PBWL pbwl, PWND pwnd, UINT flags);
PBWL InternalBuildHwndOwnerList(PBWL pbwl, PWND pwndStart, PWND pwndOwner);
#ifdef FE_IME
PBWL InternalRebuildHwndListForIMEClass(PBWL pbwl, BOOL fRemoveChild);
PWND InternalGetIMEOwner(HWND hwnd, BOOL fRetIMEWnd);
#endif
/***************************************************************************\
* xxxInternalEnumWindow
*
* History:
* 10-20-90 darrinm Ported from Win 3.0 sources.
* 02-06-91 IanJa rename: the call to lpfn can leave the critsect.
* 02-19-91 JimA Added enum access check
\***************************************************************************/
BOOL xxxInternalEnumWindow(
PWND pwndNext,
WNDENUMPROC_PWND lpfn,
LPARAM lParam,
UINT flags)
{
HWND *phwnd;
PWND pwnd;
PBWL pbwl;
BOOL fSuccess;
TL tlpwnd;
CheckLock(pwndNext);
if ((pbwl = BuildHwndList(pwndNext, flags, NULL)) == NULL)
return FALSE;
fSuccess = TRUE;
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
/*
* Lock the window before we pass it off to the app.
*/
if ((pwnd = RevalidateHwnd(*phwnd)) != NULL) {
/*
* Call the application.
*/
ThreadLockAlways(pwnd, &tlpwnd);
fSuccess = (*lpfn)(pwnd, lParam);
ThreadUnlock(&tlpwnd);
if (!fSuccess)
break;
}
}
FreeHwndList(pbwl);
return fSuccess;
}
/***************************************************************************\
* BuildHwndList
*
* History:
* 10-20-90 darrinm Ported from Win 3.0 sources.
\***************************************************************************/
#define CHWND_BWLCREATE 32
PBWL BuildHwndList(
PWND pwnd,
UINT flags,
PTHREADINFO pti)
{
PBWL pbwl;
CheckCritIn();
if ((pbwl = pbwlCache) != NULL) {
/*
* We're using the cache now; zero it out.
*/
#if DBG
pbwlCachePrev = pbwlCache;
#endif
pbwlCache = NULL;
#if DBG
{
PBWL pbwlT;
/*
* pbwlCache shouldn't be in the global linked list.
*/
for (pbwlT = gpbwlList; pbwlT != NULL; pbwlT = pbwlT->pbwlNext) {
UserAssert(pbwlT != pbwl);
}
}
#endif
} else {
/*
* sizeof(BWL) includes the first element of array.
*/
pbwl = (PBWL)UserAllocPool(sizeof(BWL) + sizeof(PWND) * CHWND_BWLCREATE,
TAG_WINDOWLIST);
if (pbwl == NULL)
return NULL;
pbwl->phwndMax = &pbwl->rghwnd[CHWND_BWLCREATE - 1];
}
pbwl->phwndNext = pbwl->rghwnd;
/*
* We'll use ptiOwner as temporary storage for the thread we're
* scanning for. It will get reset to the proper thing at the bottom
* of this routine.
*/
pbwl->ptiOwner = pti;
#ifdef OWNERLIST
if (flags & BWL_ENUMOWNERLIST) {
pbwl = InternalBuildHwndOwnerList(pbwl, pwnd, NULL);
} else {
pbwl = InternalBuildHwndList(pbwl, pwnd, flags);
}
#else
pbwl = InternalBuildHwndList(pbwl, pwnd, flags);
#endif
/*
* If phwndNext == phwndMax, it indicates that the pbwl has failed to expand.
* The list is no longer valid, so we should just bail.
*/
if (pbwl->phwndNext >= pbwl->phwndMax) {
UserAssert(pbwl->phwndNext == pbwl->phwndMax);
/*
* Even if we had picked pbwl from the global single cache (pbwlCache),
* it should have already been unlinked from the global link list when it was put in the cache.
* So we should just free it without manupilating the link pointers.
* If we have allocated the pwbl for ourselves, we can simply free it.
* In both cases, we should just call UserFreePool().
* As the side effect, it may make some room by providing a free pool block.
*/
UserFreePool(pbwl);
return NULL;
}
/*
* Stick in the terminator.
*/
*pbwl->phwndNext = (HWND)1;
#ifdef FE_IME
if (flags & BWL_ENUMIMELAST) {
UserAssert(IS_IME_ENABLED());
/*
* For IME windows.
* Rebuild window list for EnumWindows API. Because ACCESS 2.0 assumes
* the first window that is called CallBack Functions in the task is
* Q-Card Wnd. We should change the order of IME windows
*/
pbwl = InternalRebuildHwndListForIMEClass(pbwl,
(flags & BWL_REMOVEIMECHILD) == BWL_REMOVEIMECHILD);
}
#endif
/*
* Finally link this guy into the list.
*/
pbwl->ptiOwner = PtiCurrent();
pbwl->pbwlNext = gpbwlList;
gpbwlList = pbwl;
/*
* We should have given out the cache if it was available
*/
UserAssert(pbwlCache == NULL);
return pbwl;
}
/***************************************************************************\
* ExpandWindowList
*
* This routine expands a window list.
*
* 01-16-92 ScottLu Created.
\***************************************************************************/
BOOL ExpandWindowList(
PBWL *ppbwl)
{
PBWL pbwl;
PBWL pbwlT;
HWND *phwnd;
pbwl = *ppbwl;
phwnd = pbwl->phwndNext;
/*
* Map phwnd to an offset.
*/
phwnd = (HWND *)((BYTE *)phwnd - (BYTE *)pbwl);
/*
* Increase size of BWL by 8 slots. (8 + 1) is
* added since phwnd is "sizeof(HWND)" less
* than actual size of handle.
*/
pbwlT = (PBWL)UserReAllocPool((HANDLE)pbwl,
PtrToUlong(phwnd) + sizeof(PWND),
PtrToUlong(phwnd) + (BWL_CHWNDMORE + 1) * sizeof(PWND),
TAG_WINDOWLIST);
/*
* Did alloc succeed?
*/
if (pbwlT != NULL)
pbwl = pbwlT; /* Yes, use new block. */
/*
* Map phwnd back into a pointer.
*/
phwnd = (HWND *)((ULONG_PTR)pbwl + (ULONG_PTR)phwnd);
/*
* Did ReAlloc() fail?
*/
if (pbwlT == NULL) {
RIPMSG0(RIP_WARNING, "ExpandWindowList: out of memory.");
return FALSE;
}
/*
* Reset phwndMax.
*/
pbwl->phwndNext = phwnd;
pbwl->phwndMax = phwnd + BWL_CHWNDMORE;
*ppbwl = pbwl;
return TRUE;
}
#ifdef OWNERLIST
/***************************************************************************\
* InternalBuildHwndOwnerList
*
* Builds an hwnd list sorted by owner. Ownees go first. Shutdown uses this for
* WM_CLOSE messages.
*
* 01-16-93 ScottLu Created.
\***************************************************************************/
PBWL InternalBuildHwndOwnerList(
PBWL pbwl,
PWND pwndStart,
PWND pwndOwner)
{
PWND pwndT;
/*
* Put ownees first in the list.
*/
for (pwndT = pwndStart; pwndT != NULL; pwndT = pwndT->spwndNext) {
/*
* Not the ownee we're looking for? Continue.
*/
if (pwndT->spwndOwner != pwndOwner)
continue;
/*
* Only top level windows that have system menus (the ones that can
* receive a WM_CLOSE message).
*/
if (!TestWF(pwndT, WFSYSMENU))
continue;
/*
* Add it and its ownees to our list.
*/
pbwl = InternalBuildHwndOwnerList(pbwl, pwndStart, pwndT);
/*
* If ExpandWindowList() failed in recursive calls,
* just bail here.
*/
if (pbwl->phwndNext >= pbwl->phwndMax) {
UserAssert(pbwl->phwndNext == pbwl->phwndMax);
return pbwl;
}
UserAssert(pbwl->phwndNext < pbwl->phwndMax);
}
/*
* Finally add this owner to our list.
*/
if (pwndOwner != NULL) {
UserAssert(pbwl->phwndNext < pbwl->phwndMax);
*pbwl->phwndNext = HWq(pwndOwner);
pbwl->phwndNext++;
if (pbwl->phwndNext == pbwl->phwndMax) {
if (!ExpandWindowList(&pbwl))
return pbwl;
}
}
return pbwl;
}
#endif
/***************************************************************************\
* InternalBuildHwndList
*
* History:
* 10-20-90 darrinm Ported from Win 3.0 sources.
\***************************************************************************/
#define BWLGROW 8
PBWL InternalBuildHwndList(
PBWL pbwl,
PWND pwnd,
UINT flags)
{
/*
* NOTE: pbwl->phwndNext is used as a place to keep
* the phwnd across calls to InternalBuildHwndList().
* This is OK since we don't link pbwl into the list
* of pbwl's until after we've finished enumerating windows.
*/
while (pwnd != NULL) {
/*
* Make sure it matches the thread id, if there is one.
*/
if (pbwl->ptiOwner == NULL || pbwl->ptiOwner == GETPTI(pwnd)) {
UserAssert(pbwl->phwndNext < pbwl->phwndMax);
*pbwl->phwndNext = HWq(pwnd);
pbwl->phwndNext++;
if (pbwl->phwndNext == pbwl->phwndMax) {
#if EMULATE_EXPAND_FAILURE
static int n = 0;
if (++n % 32 == 0) {
RIPMSG0(RIP_WARNING, "InternalBuildHwndList: emulating ExpandWindowList failure.");
break;
}
#endif
if (!ExpandWindowList(&pbwl))
break;
}
}
/*
* Should we step through the Child windows?
*/
if ((flags & BWL_ENUMCHILDREN) && pwnd->spwndChild != NULL) {
pbwl = InternalBuildHwndList(pbwl, pwnd->spwndChild, BWL_ENUMLIST | BWL_ENUMCHILDREN);
/*
* If ExpandWindowList() failed in the recursive call,
* we should just bail.
*/
if (pbwl->phwndNext >= pbwl->phwndMax) {
UserAssert(pbwl->phwndNext == pbwl->phwndMax);
RIPMSG1(RIP_WARNING, "InternalBuildHwndList: failed to expand BWL in enumerating children. pbwl=%#p", pbwl);
break;
}
UserAssert(pbwl->phwndNext < pbwl->phwndMax);
}
/*
* Are we enumerating only one window?
*/
if (!(flags & BWL_ENUMLIST))
break;
pwnd = pwnd->spwndNext;
}
return pbwl;
}
/***************************************************************************\
* FreeHwndList
*
* History:
* 10-20-90 darrinm Ported from Win 3.0 sources.
\***************************************************************************/
void FreeHwndList(
PBWL pbwl)
{
PBWL *ppbwl;
PBWL pbwlT;
CheckCritIn();
/*
* We should never have an active bwl that is the free cached bwl
*/
UserAssert(pbwl != pbwlCache);
/*
* Unlink this bwl from the list.
*/
for (ppbwl = &gpbwlList; *ppbwl != NULL; ppbwl = &(*ppbwl)->pbwlNext) {
if (*ppbwl == pbwl) {
*ppbwl = pbwl->pbwlNext;
/*
* If the cache is empty or this pbwl is larger than the
* cached one, save the pbwl there.
*/
if (pbwlCache == NULL) {
pbwlCache = pbwl;
} else if ((pbwl->phwndMax - pbwl->rghwnd) >
(pbwlCache->phwndMax - pbwlCache->rghwnd)) {
pbwlT = pbwlCache;
pbwlCache = pbwl;
UserFreePool((HANDLE)pbwlT);
} else {
UserFreePool((HANDLE)pbwl);
}
return;
}
}
/*
* Assert if we couldn't find the pbwl in the list...
*/
UserAssert(FALSE);
}
#ifdef FE_IME
PBWL InternalRebuildHwndListForIMEClass(
PBWL pbwl,
BOOL fRemoveChild)
{
PHWND phwndIME, phwndIMECur, phwnd, phwndCur;
DWORD dwSize = (DWORD)((BYTE *)pbwl->phwndMax - (BYTE *)pbwl) + sizeof(HWND);
phwndIMECur = phwndIME = (PHWND)UserAllocPool(dwSize, TAG_WINDOWLIST);
if (phwndIME == NULL) {
RIPMSG0(RIP_WARNING, "RebuildHwndListForIMEClass: invalid phwndIME");
return pbwl;
}
phwndCur = pbwl->rghwnd;
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
PWND pwndIMEOwner;
// Find the IME class or CS_IME window in the owners of hwnd.
// When fRemoveChild is TRUE, we want IME class window as the return
// of InternalGetIMEOwner.
if (pwndIMEOwner = InternalGetIMEOwner(*phwnd, fRemoveChild)) {
try {
if (!fRemoveChild ||
(pwndIMEOwner->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME] &&
((PIMEWND)pwndIMEOwner)->pimeui != NULL &&
!ProbeAndReadStructure(((PIMEWND)pwndIMEOwner)->pimeui, IMEUI).fChildThreadDef))
{
*phwndIMECur++ = *phwnd;
}
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
}
} else {
*phwndCur++ = *phwnd;
}
}
// Here NULL s used as terminator.
*phwndIMECur = NULL;
phwndIMECur = phwndIME;
while(*phwndIMECur != NULL)
*phwndCur++ = *phwndIMECur++;
if (*phwndCur != (HWND)1) {
RIPMSG0(RIP_WARNING, "RebuildHwndListForIMEClass: Where is terminator?");
*phwndCur = (HWND)1;
}
UserFreePool((HANDLE)phwndIME);
return pbwl;
}
PWND InternalGetIMEOwner(
HWND hwnd,
BOOL fRetIMEWnd)
{
PWND pwnd, pwndT, pwndIME;
pwnd = RevalidateHwnd(hwnd);
if (pwnd == NULL)
return NULL;
for (pwndT = pwnd; pwndT != NULL; pwndT = pwndT->spwndOwner) {
if (TestCF(pwndT,CFIME) ||
pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) {
if (!fRetIMEWnd)
return pwndT;
pwndIME = pwndT;
while (pwndT && (pwndT->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]))
pwndT = pwndT->spwndOwner;
if (pwndT)
pwndIME = pwndT;
else
RIPMSG0(RIP_WARNING, "Can't find IME Class window");
return pwndIME;
}
}
return NULL;
}
#endif