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

Generated on Sat May 15 19:39:56 2004 for test by doxygen 1.3.7