test: enumwin.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# enumwin.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: enumwin.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Contains the EnumWindows API, BuildHwndList and related functions.
    00007 *
    00008 * History:
    00009 * 10-20-90 darrinm      Created.
    00010 * ??-??-?? ianja        Added Revalidation code
    00011 * 02-19-91 JimA         Added enum access checks
    00012 \***************************************************************************/
    00013
    00014 #include "precomp.h"
    00015 #pragma hdrstop
    00016
    00017 PBWL pbwlCache;
    00018
    00019 #if DBG
    00020 PBWL pbwlCachePrev;
    00021 #endif
    00022
    00023 PBWL InternalBuildHwndList(PBWL pbwl, PWND pwnd, UINT flags);
    00024 PBWL InternalBuildHwndOwnerList(PBWL pbwl, PWND pwndStart, PWND pwndOwner);
    00025 #ifdef FE_IME
    00026 PBWL InternalRebuildHwndListForIMEClass(PBWL pbwl, BOOL fRemoveChild);
    00027 PWND InternalGetIMEOwner(HWND hwnd, BOOL fRetIMEWnd);
    00028 #endif
    00029
    00030
    00031 /***************************************************************************\
    00032 * xxxInternalEnumWindow
    00033 *
    00034 * History:
    00035 * 10-20-90 darrinm      Ported from Win 3.0 sources.
    00036 * 02-06-91 IanJa        rename: the call to lpfn can leave the critsect.
    00037 * 02-19-91 JimA         Added enum access check
    00038 \***************************************************************************/
    00039
    00040 BOOL xxxInternalEnumWindow(
    00041     PWND pwndNext,
    00042     WNDENUMPROC_PWND lpfn,
    00043     LPARAM lParam,
    00044     UINT flags)
    00045 {
    00046     HWND *phwnd;
    00047     PWND pwnd;
    00048     PBWL pbwl;
    00049     BOOL fSuccess;
    00050     TL tlpwnd;
    00051
    00052     CheckLock(pwndNext);
    00053
    00054     if ((pbwl = BuildHwndList(pwndNext, flags, NULL)) == NULL)
    00055         return FALSE;
    00056
    00057     fSuccess = TRUE;
    00058     for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
    00059
    00060         /*
    00061          * Lock the window before we pass it off to the app.
    00062          */
    00063         if ((pwnd = RevalidateHwnd(*phwnd)) != NULL) {
    00064
    00065             /*
    00066              * Call the application.
    00067              */
    00068             ThreadLockAlways(pwnd, &tlpwnd);
    00069             fSuccess = (*lpfn)(pwnd, lParam);
    00070             ThreadUnlock(&tlpwnd);
    00071             if (!fSuccess)
    00072                 break;
    00073         }
    00074     }
    00075
    00076     FreeHwndList(pbwl);
    00077
    00078     return fSuccess;
    00079 }
    00080
    00081
    00082 /***************************************************************************\
    00083 * BuildHwndList
    00084 *
    00085 * History:
    00086 * 10-20-90 darrinm      Ported from Win 3.0 sources.
    00087 \***************************************************************************/
    00088
    00089 #define CHWND_BWLCREATE 32
    00090
    00091 PBWL BuildHwndList(
    00092     PWND pwnd,
    00093     UINT flags,
    00094     PTHREADINFO pti)
    00095 {
    00096     PBWL pbwl;
    00097
    00098     CheckCritIn();
    00099
    00100     if ((pbwl = pbwlCache) != NULL) {
    00101
    00102         /*
    00103          * We're using the cache now; zero it out.
    00104          */
    00105 #if DBG
    00106         pbwlCachePrev = pbwlCache;
    00107 #endif
    00108         pbwlCache = NULL;
    00109
    00110 #if DBG
    00111         {
    00112             PBWL pbwlT;
    00113             /*
    00114              * pbwlCache shouldn't be in the global linked list.
    00115              */
    00116             for (pbwlT = gpbwlList; pbwlT != NULL; pbwlT = pbwlT->pbwlNext) {
    00117                 UserAssert(pbwlT != pbwl);
    00118             }
    00119         }
    00120 #endif
    00121     } else {
    00122
    00123         /*
    00124          * sizeof(BWL) includes the first element of array.
    00125          */
    00126         pbwl = (PBWL)UserAllocPool(sizeof(BWL) + sizeof(PWND) * CHWND_BWLCREATE,
    00127                 TAG_WINDOWLIST);
    00128         if (pbwl == NULL)
    00129             return NULL;
    00130
    00131         pbwl->phwndMax = &pbwl->rghwnd[CHWND_BWLCREATE - 1];
    00132     }
    00133     pbwl->phwndNext = pbwl->rghwnd;
    00134
    00135     /*
    00136      * We'll use ptiOwner as temporary storage for the thread we're
    00137      * scanning for. It will get reset to the proper thing at the bottom
    00138      * of this routine.
    00139      */
    00140     pbwl->ptiOwner = pti;
    00141
    00142 #ifdef OWNERLIST
    00143     if (flags & BWL_ENUMOWNERLIST) {
    00144         pbwl = InternalBuildHwndOwnerList(pbwl, pwnd, NULL);
    00145     } else {
    00146         pbwl = InternalBuildHwndList(pbwl, pwnd, flags);
    00147     }
    00148 #else
    00149     pbwl = InternalBuildHwndList(pbwl, pwnd, flags);
    00150 #endif
    00151
    00152     /*
    00153      * If phwndNext == phwndMax, it indicates that the pbwl has failed to expand.
    00154      * The list is no longer valid, so we should just bail.
    00155      */
    00156     if (pbwl->phwndNext >= pbwl->phwndMax) {
    00157         UserAssert(pbwl->phwndNext == pbwl->phwndMax);
    00158         /*
    00159          * Even if we had picked pbwl from the global single cache (pbwlCache),
    00160          * it should have already been unlinked from the global link list when it was put in the cache.
    00161          * So we should just free it without manupilating the link pointers.
    00162          * If we have allocated the pwbl for ourselves, we can simply free it.
    00163          * In both cases, we should just call UserFreePool().
    00164          * As the side effect, it may make some room by providing a free pool block.
    00165          */
    00166         UserFreePool(pbwl);
    00167         return NULL;
    00168     }
    00169
    00170     /*
    00171      * Stick in the terminator.
    00172      */
    00173     *pbwl->phwndNext = (HWND)1;
    00174
    00175 #ifdef FE_IME
    00176     if (flags & BWL_ENUMIMELAST) {
    00177         UserAssert(IS_IME_ENABLED());
    00178         /*
    00179          * For IME windows.
    00180          * Rebuild window list for EnumWindows API. Because ACCESS 2.0 assumes
    00181          * the first window that is called CallBack Functions in the task is
    00182          * Q-Card Wnd. We should change the order of IME windows
    00183          */
    00184         pbwl = InternalRebuildHwndListForIMEClass(pbwl,
    00185                     (flags & BWL_REMOVEIMECHILD) == BWL_REMOVEIMECHILD);
    00186     }
    00187 #endif
    00188
    00189     /*
    00190      * Finally link this guy into the list.
    00191      */
    00192     pbwl->ptiOwner = PtiCurrent();
    00193     pbwl->pbwlNext = gpbwlList;
    00194     gpbwlList = pbwl;
    00195
    00196
    00197     /*
    00198      * We should have given out the cache if it was available
    00199      */
    00200     UserAssert(pbwlCache == NULL);
    00201
    00202     return pbwl;
    00203 }
    00204
    00205 /***************************************************************************\
    00206 * ExpandWindowList
    00207 *
    00208 * This routine expands a window list.
    00209 *
    00210 * 01-16-92 ScottLu      Created.
    00211 \***************************************************************************/
    00212
    00213 BOOL ExpandWindowList(
    00214     PBWL *ppbwl)
    00215 {
    00216     PBWL pbwl;
    00217     PBWL pbwlT;
    00218     HWND *phwnd;
    00219
    00220     pbwl = *ppbwl;
    00221     phwnd = pbwl->phwndNext;
    00222
    00223     /*
    00224      * Map phwnd to an offset.
    00225      */
    00226     phwnd = (HWND *)((BYTE *)phwnd - (BYTE *)pbwl);
    00227
    00228     /*
    00229      * Increase size of BWL by 8 slots.  (8 + 1) is
    00230      * added since phwnd is "sizeof(HWND)" less
    00231      * than actual size of handle.
    00232      */
    00233     pbwlT = (PBWL)UserReAllocPool((HANDLE)pbwl,
    00234             PtrToUlong(phwnd) + sizeof(PWND),
    00235             PtrToUlong(phwnd) + (BWL_CHWNDMORE + 1) * sizeof(PWND),
    00236             TAG_WINDOWLIST);
    00237
    00238     /*
    00239      * Did alloc succeed?
    00240      */
    00241     if (pbwlT != NULL)
    00242         pbwl = pbwlT;                 /* Yes, use new block. */
    00243
    00244     /*
    00245      * Map phwnd back into a pointer.
    00246      */
    00247     phwnd = (HWND *)((ULONG_PTR)pbwl + (ULONG_PTR)phwnd);
    00248
    00249     /*
    00250      * Did ReAlloc() fail?
    00251      */
    00252     if (pbwlT == NULL) {
    00253         RIPMSG0(RIP_WARNING, "ExpandWindowList: out of memory.");
    00254         return FALSE;
    00255     }
    00256
    00257     /*
    00258      * Reset phwndMax.
    00259      */
    00260     pbwl->phwndNext = phwnd;
    00261     pbwl->phwndMax = phwnd + BWL_CHWNDMORE;
    00262
    00263     *ppbwl = pbwl;
    00264
    00265     return TRUE;
    00266 }
    00267
    00268 #ifdef OWNERLIST
    00269
    00270 /***************************************************************************\
    00271 * InternalBuildHwndOwnerList
    00272 *
    00273 * Builds an hwnd list sorted by owner. Ownees go first. Shutdown uses this for
    00274 * WM_CLOSE messages.
    00275 *
    00276 * 01-16-93 ScottLu      Created.
    00277 \***************************************************************************/
    00278
    00279 PBWL InternalBuildHwndOwnerList(
    00280     PBWL pbwl,
    00281     PWND pwndStart,
    00282     PWND pwndOwner)
    00283 {
    00284     PWND pwndT;
    00285
    00286     /*
    00287      * Put ownees first in the list.
    00288      */
    00289     for (pwndT = pwndStart; pwndT != NULL; pwndT = pwndT->spwndNext) {
    00290
    00291         /*
    00292          * Not the ownee we're looking for? Continue.
    00293          */
    00294         if (pwndT->spwndOwner != pwndOwner)
    00295             continue;
    00296
    00297         /*
    00298          * Only top level windows that have system menus (the ones that can
    00299          * receive a WM_CLOSE message).
    00300          */
    00301         if (!TestWF(pwndT, WFSYSMENU))
    00302             continue;
    00303
    00304         /*
    00305          * Add it and its ownees to our list.
    00306          */
    00307         pbwl = InternalBuildHwndOwnerList(pbwl, pwndStart, pwndT);
    00308
    00309         /*
    00310          * If ExpandWindowList() failed in recursive calls,
    00311          * just bail here.
    00312          */
    00313         if (pbwl->phwndNext >= pbwl->phwndMax) {
    00314             UserAssert(pbwl->phwndNext == pbwl->phwndMax);
    00315             return pbwl;
    00316         }
    00317         UserAssert(pbwl->phwndNext < pbwl->phwndMax);
    00318     }
    00319
    00320     /*
    00321      * Finally add this owner to our list.
    00322      */
    00323     if (pwndOwner != NULL) {
    00324         UserAssert(pbwl->phwndNext < pbwl->phwndMax);
    00325         *pbwl->phwndNext = HWq(pwndOwner);
    00326         pbwl->phwndNext++;
    00327         if (pbwl->phwndNext == pbwl->phwndMax) {
    00328             if (!ExpandWindowList(&pbwl))
    00329                 return pbwl;
    00330         }
    00331     }
    00332
    00333     return pbwl;
    00334 }
    00335
    00336 #endif
    00337
    00338 /***************************************************************************\
    00339 * InternalBuildHwndList
    00340 *
    00341 * History:
    00342 * 10-20-90 darrinm      Ported from Win 3.0 sources.
    00343 \***************************************************************************/
    00344
    00345 #define BWLGROW 8
    00346
    00347 PBWL InternalBuildHwndList(
    00348     PBWL pbwl,
    00349     PWND pwnd,
    00350     UINT flags)
    00351 {
    00352     /*
    00353      * NOTE: pbwl->phwndNext is used as a place to keep
    00354      *       the phwnd across calls to InternalBuildHwndList().
    00355      *       This is OK since we don't link pbwl into the list
    00356      *       of pbwl's until after we've finished enumerating windows.
    00357      */
    00358
    00359     while (pwnd != NULL) {
    00360         /*
    00361          * Make sure it matches the thread id, if there is one.
    00362          */
    00363         if (pbwl->ptiOwner == NULL || pbwl->ptiOwner == GETPTI(pwnd)) {
    00364             UserAssert(pbwl->phwndNext < pbwl->phwndMax);
    00365             *pbwl->phwndNext = HWq(pwnd);
    00366             pbwl->phwndNext++;
    00367             if (pbwl->phwndNext == pbwl->phwndMax) {
    00368 #if EMULATE_EXPAND_FAILURE
    00369                 static int n = 0;
    00370                 if (++n % 32 == 0) {
    00371                     RIPMSG0(RIP_WARNING, "InternalBuildHwndList: emulating ExpandWindowList failure.");
    00372                     break;
    00373                 }
    00374 #endif
    00375                 if (!ExpandWindowList(&pbwl))
    00376                     break;
    00377             }
    00378         }
    00379
    00380         /*
    00381          * Should we step through the Child windows?
    00382          */
    00383         if ((flags & BWL_ENUMCHILDREN) && pwnd->spwndChild != NULL) {
    00384             pbwl = InternalBuildHwndList(pbwl, pwnd->spwndChild, BWL_ENUMLIST | BWL_ENUMCHILDREN);
    00385             /*
    00386              * If ExpandWindowList() failed in the recursive call,
    00387              * we should just bail.
    00388              */
    00389             if (pbwl->phwndNext >= pbwl->phwndMax) {
    00390                 UserAssert(pbwl->phwndNext == pbwl->phwndMax);
    00391                 RIPMSG1(RIP_WARNING, "InternalBuildHwndList: failed to expand BWL in enumerating children. pbwl=%#p", pbwl);
    00392                 break;
    00393             }
    00394             UserAssert(pbwl->phwndNext < pbwl->phwndMax);
    00395         }
    00396
    00397         /*
    00398          * Are we enumerating only one window?
    00399          */
    00400         if (!(flags & BWL_ENUMLIST))
    00401             break;
    00402
    00403         pwnd = pwnd->spwndNext;
    00404     }
    00405
    00406     return pbwl;
    00407 }
    00408
    00409
    00410 /***************************************************************************\
    00411 * FreeHwndList
    00412 *
    00413 * History:
    00414 * 10-20-90 darrinm      Ported from Win 3.0 sources.
    00415 \***************************************************************************/
    00416
    00417 void FreeHwndList(
    00418     PBWL pbwl)
    00419 {
    00420     PBWL *ppbwl;
    00421     PBWL pbwlT;
    00422
    00423     CheckCritIn();
    00424
    00425     /*
    00426      * We should never have an active bwl that is the free cached bwl
    00427      */
    00428     UserAssert(pbwl != pbwlCache);
    00429
    00430     /*
    00431      * Unlink this bwl from the list.
    00432      */
    00433     for (ppbwl = &gpbwlList; *ppbwl != NULL; ppbwl = &(*ppbwl)->pbwlNext) {
    00434         if (*ppbwl == pbwl) {
    00435             *ppbwl = pbwl->pbwlNext;
    00436
    00437             /*
    00438              * If the cache is empty or this pbwl is larger than the
    00439              * cached one, save the pbwl there.
    00440              */
    00441             if (pbwlCache == NULL) {
    00442                 pbwlCache = pbwl;
    00443             } else if ((pbwl->phwndMax - pbwl->rghwnd) >
    00444                        (pbwlCache->phwndMax - pbwlCache->rghwnd)) {
    00445                 pbwlT = pbwlCache;
    00446                 pbwlCache = pbwl;
    00447                 UserFreePool((HANDLE)pbwlT);
    00448             } else {
    00449                 UserFreePool((HANDLE)pbwl);
    00450             }
    00451             return;
    00452         }
    00453     }
    00454
    00455     /*
    00456      * Assert if we couldn't find the pbwl in the list...
    00457      */
    00458     UserAssert(FALSE);
    00459 }
    00460
    00461 #ifdef FE_IME
    00462
    00463 PBWL InternalRebuildHwndListForIMEClass(
    00464     PBWL pbwl,
    00465     BOOL fRemoveChild)
    00466 {
    00467     PHWND phwndIME, phwndIMECur, phwnd, phwndCur;
    00468     DWORD dwSize = (DWORD)((BYTE *)pbwl->phwndMax - (BYTE *)pbwl) + sizeof(HWND);
    00469
    00470     phwndIMECur = phwndIME = (PHWND)UserAllocPool(dwSize, TAG_WINDOWLIST);
    00471     if (phwndIME == NULL) {
    00472         RIPMSG0(RIP_WARNING, "RebuildHwndListForIMEClass: invalid phwndIME");
    00473         return pbwl;
    00474     }
    00475
    00476     phwndCur = pbwl->rghwnd;
    00477
    00478     for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
    00479         PWND pwndIMEOwner;
    00480
    00481         // Find the IME class or CS_IME window in the owners of hwnd.
    00482         // When fRemoveChild is TRUE, we want IME class window as the return
    00483         // of InternalGetIMEOwner.
    00484         if (pwndIMEOwner = InternalGetIMEOwner(*phwnd, fRemoveChild)) {
    00485             try {
    00486                 if (!fRemoveChild ||
    00487                     (pwndIMEOwner->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME] &&
    00488                       ((PIMEWND)pwndIMEOwner)->pimeui != NULL &&
    00489                      !ProbeAndReadStructure(((PIMEWND)pwndIMEOwner)->pimeui, IMEUI).fChildThreadDef))
    00490                 {
    00491                     *phwndIMECur++ = *phwnd;
    00492                 }
    00493             } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
    00494             }
    00495         } else {
    00496             *phwndCur++ = *phwnd;
    00497         }
    00498     }
    00499
    00500     // Here NULL s used as terminator.
    00501     *phwndIMECur = NULL;
    00502
    00503     phwndIMECur = phwndIME;
    00504     while(*phwndIMECur != NULL)
    00505         *phwndCur++ = *phwndIMECur++;
    00506
    00507     if (*phwndCur != (HWND)1) {
    00508         RIPMSG0(RIP_WARNING, "RebuildHwndListForIMEClass: Where is terminator?");
    00509         *phwndCur = (HWND)1;
    00510     }
    00511
    00512     UserFreePool((HANDLE)phwndIME);
    00513     return pbwl;
    00514 }
    00515
    00516 PWND InternalGetIMEOwner(
    00517     HWND hwnd,
    00518     BOOL fRetIMEWnd)
    00519 {
    00520     PWND pwnd, pwndT, pwndIME;
    00521
    00522     pwnd = RevalidateHwnd(hwnd);
    00523     if (pwnd == NULL)
    00524         return NULL;
    00525
    00526     for (pwndT = pwnd; pwndT != NULL; pwndT = pwndT->spwndOwner) {
    00527         if (TestCF(pwndT,CFIME) ||
    00528                 pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) {
    00529
    00530             if (!fRetIMEWnd)
    00531                 return pwndT;
    00532
    00533             pwndIME = pwndT;
    00534
    00535             while (pwndT && (pwndT->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]))
    00536                 pwndT = pwndT->spwndOwner;
    00537
    00538             if (pwndT)
    00539                 pwndIME = pwndT;
    00540             else
    00541                 RIPMSG0(RIP_WARNING, "Can't find IME Class window");
    00542
    00543             return pwndIME;
    00544         }
    00545     }
    00546
    00547     return NULL;
    00548 }
    00549
    00550 #endif