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

dlgmgrc.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: dlgmgrc.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains client side dialog functionality 00007 * 00008 * History: 00009 * 15-Dec-1993 JohnC Pulled functions from user\server. 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 00016 /***************************************************************************\ 00017 * UT_PrevGroupItem 00018 * 00019 * History: 00020 \***************************************************************************/ 00021 00022 PWND UT_PrevGroupItem( 00023 PWND pwndDlg, 00024 PWND pwndCurrent) 00025 { 00026 PWND pwnd, pwndPrev; 00027 00028 if (pwndCurrent == NULL || !TestWF(pwndCurrent, WFGROUP)) 00029 return _PrevControl(pwndDlg, pwndCurrent, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED); 00030 00031 pwndPrev = pwndCurrent; 00032 00033 while (TRUE) { 00034 pwnd = _NextControl(pwndDlg, pwndPrev, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED); 00035 00036 if (TestWF(pwnd, WFGROUP) || pwnd == pwndCurrent) 00037 return pwndPrev; 00038 00039 pwndPrev = pwnd; 00040 } 00041 } 00042 00043 00044 /***************************************************************************\ 00045 * UT_NextGroupItem 00046 * 00047 * History: 00048 \***************************************************************************/ 00049 00050 PWND UT_NextGroupItem( 00051 PWND pwndDlg, 00052 PWND pwndCurrent) 00053 { 00054 PWND pwnd, pwndNext; 00055 00056 pwnd = _NextControl(pwndDlg, pwndCurrent, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED); 00057 00058 if (pwndCurrent == NULL || !TestWF(pwnd, WFGROUP)) 00059 return pwnd; 00060 00061 pwndNext = pwndCurrent; 00062 00063 while (!TestWF(pwndNext, WFGROUP)) { 00064 pwnd = _PrevControl(pwndDlg, pwndNext, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED); 00065 if (pwnd == pwndCurrent) 00066 return pwndNext; 00067 pwndNext = pwnd; 00068 } 00069 00070 return pwndNext; 00071 } 00072 00073 /***************************************************************************\ 00074 * _PrevControl 00075 * 00076 * History: 00077 \***************************************************************************/ 00078 PWND _PrevControl( 00079 PWND pwndRoot, 00080 PWND pwndStart, 00081 UINT uFlags) 00082 { 00083 BOOL fFirstFound; 00084 PWND pwndNext; 00085 PWND pwnd, pwndFirst; 00086 00087 if (!pwndStart) 00088 return(NULL); 00089 00090 UserAssert(pwndRoot != pwndStart); 00091 UserAssert(!TestWF(pwndStart, WEFCONTROLPARENT)); 00092 00093 pwnd = _NextControl(pwndRoot, NULL, uFlags); 00094 00095 pwndFirst = pwnd; 00096 fFirstFound = FALSE; 00097 while (pwndNext = _NextControl(pwndRoot, pwnd, uFlags)) { 00098 00099 if (pwndNext == pwndStart) 00100 break; 00101 00102 if (pwndNext == pwndFirst) { 00103 if (fFirstFound) { 00104 RIPMSG0(RIP_WARNING, "_PrevControl: Loop Detected"); 00105 break; 00106 } else { 00107 fFirstFound = TRUE; 00108 } 00109 } 00110 00111 pwnd = pwndNext; 00112 } 00113 00114 return pwnd; 00115 } 00116 /***************************************************************************\ 00117 * 00118 * GetChildControl() 00119 * 00120 * Gets valid ancestor of given window. 00121 * A valid dialog control is a direct descendant of a "form" control. 00122 * 00123 \***************************************************************************/ 00124 00125 PWND _GetChildControl(PWND pwndRoot, PWND pwndChild) { 00126 PWND pwndControl = NULL; 00127 00128 while (pwndChild && TestwndChild(pwndChild) && (pwndChild != pwndRoot)) { 00129 pwndControl = pwndChild; 00130 pwndChild = REBASEPWND(pwndChild, spwndParent); 00131 00132 if (TestWF(pwndChild, WEFCONTROLPARENT)) 00133 break; 00134 } 00135 00136 return(pwndControl); 00137 } 00138 00139 /***************************************************************************\ 00140 * 00141 * _NextSibblingOrAncestor 00142 * 00143 * Called by _NextControl. It returns the next control to pwndStart. If there 00144 * is a next window (pwndStart->spwndNext), then that is it. 00145 * Otherwise, the next control is up the parent chain. However, if it's already 00146 * at the top of the chain (pwndRoot == pwndStart->spwndParent), then the next 00147 * control is the first child of pwndRoot. But if it's not at the top of the chain, 00148 * then the next control is pwndStart->spwndParent or an ancestor. 00149 * 00150 \***************************************************************************/ 00151 PWND _NextSibblingOrAncestor (PWND pwndRoot, PWND pwndStart) 00152 { 00153 PWND pwndParent; 00154 #if DBG 00155 PWND pwndNext; 00156 #endif 00157 00158 // If there is a sibbling, go for it 00159 if (pwndStart->spwndNext != NULL) { 00160 return (REBASEALWAYS(pwndStart, spwndNext)); 00161 } 00162 00163 // If it cannot go up the parent chain, then return the first sibbling. 00164 pwndParent = REBASEALWAYS(pwndStart, spwndParent); 00165 if (pwndParent == pwndRoot) { 00166 // Note that if pwndStart doesn't have any sibblings, 00167 // this will return pwndStart again 00168 return (REBASEALWAYS(pwndParent, spwndChild)); 00169 } 00170 00171 00172 // Otherwise walk up the parent chain looking for the first window with 00173 // a WS_EX_CONTROLPARENT parent. 00174 00175 #if DBG 00176 pwndNext = 00177 #else 00178 return 00179 #endif 00180 _GetChildControl(pwndRoot, pwndParent); 00181 00182 #if DBG 00183 if ((pwndNext != pwndParent) || !TestWF(pwndParent, WEFCONTROLPARENT)) { 00184 // Code looping through the controls in a dialog might go into an infinite 00185 // loop because of this (i.e., xxxRemoveDefaultButton, _GetNextDlgTabItem,..) 00186 // We've walked up the parent chain but will never walk down the child chain again 00187 // because there is a NON WS_EX_CONTROLPARENT parent window somewhere in the chain. 00188 RIPMSG0 (RIP_ERROR, "_NextSibblingOrAncestor: Non WS_EX_CONTROLPARENT window in parent chain"); 00189 } 00190 return pwndNext; 00191 #endif 00192 } 00193 /***************************************************************************\ 00194 * 00195 * _NextControl() 00196 * 00197 * It searches for the next NON WS_EX_CONTROLPARENT control following pwndStart. 00198 * If pwndStart is NULL, the search begins with pwndRoot's first child; 00199 * otherwise, it starts with the control next to pwndStart. 00200 * This is a depth-first search that can start anywhere in the window tree. 00201 * uFlags determine what WS_EX_CONTROLPARENT windows should be skipped or recursed into. 00202 * If skipping a window, the search moves to the next control (see _NextSibblingOrAncestor); 00203 * otherwise, the search walks down the child chain (recursive call). 00204 * If the search fails, it returns pwndRoot. 00205 * 00206 \***************************************************************************/ 00207 PWND _NextControl( 00208 PWND pwndRoot, 00209 PWND pwndStart, 00210 UINT uFlags) 00211 { 00212 BOOL fSkip, fAncestor; 00213 PWND pwndLast, pwndSibblingLoop; 00214 /* Bug 272874 - joejo 00215 * 00216 * Stop infinite loop by only looping a finite number of times and 00217 * then bailing. 00218 */ 00219 int nLoopCount = 0; 00220 00221 UserAssert (pwndRoot != NULL); 00222 00223 if (pwndStart == NULL) { 00224 // Start with pwndRoot's first child 00225 pwndStart = REBASEPWND(pwndRoot, spwndChild); 00226 pwndLast = pwndStart; 00227 fAncestor = FALSE; 00228 } else { 00229 UserAssert ((pwndRoot != pwndStart) && _IsDescendant(pwndRoot, pwndStart)); 00230 00231 // Save starting handle and get next one 00232 pwndLast = pwndStart; 00233 pwndSibblingLoop = pwndStart; 00234 fAncestor = TRUE; 00235 goto TryNextOne; 00236 } 00237 00238 00239 // If no more controls, game over 00240 if (pwndStart == NULL) { 00241 return pwndRoot; 00242 } 00243 00244 // Search for a non WS_EX_CONTROLPARENT window; if a window should be skipped, 00245 // try its spwndNext; otherwise, walk down its child chain. 00246 pwndSibblingLoop = pwndStart; 00247 do { 00248 00249 //If not WS_EX_CONTROLPARENT parent, done. 00250 if (!TestWF(pwndStart, WEFCONTROLPARENT)) { 00251 return pwndStart; 00252 } 00253 00254 // Do they want to skip this window? 00255 fSkip = ((uFlags & CWP_SKIPINVISIBLE) && !TestWF(pwndStart, WFVISIBLE)) 00256 || ((uFlags & CWP_SKIPDISABLED) && TestWF(pwndStart, WFDISABLED)); 00257 00258 00259 // Remember the current window 00260 pwndLast = pwndStart; 00261 00262 // Walk down child chain? 00263 if (!fSkip && !fAncestor) { 00264 pwndStart = _NextControl (pwndStart, NULL, uFlags); 00265 // If it found one, done. 00266 if (pwndStart != pwndLast) { 00267 return pwndStart; 00268 } 00269 } 00270 00271 TryNextOne: 00272 // Try the next one. 00273 pwndStart = _NextSibblingOrAncestor (pwndRoot, pwndStart); 00274 if (pwndStart == NULL) { 00275 break; 00276 } 00277 00278 // If parents are the same, we are still in the same sibbling chain 00279 if (pwndLast->spwndParent == pwndStart->spwndParent) { 00280 // If we had just moved up the parent chain last time around, 00281 // mark this as the beginning of the new sibbling chain. 00282 // Otherwise, check if we've looped through all sibblings already. 00283 if (fAncestor) { 00284 // Beggining of new sibbling chain. 00285 pwndSibblingLoop = pwndStart; 00286 } else if (pwndStart == pwndSibblingLoop) { 00287 // Already visited all sibblings, so done. 00288 break; 00289 } 00290 fAncestor = FALSE; 00291 } else { 00292 // We must have moved up the parent chain, so don't 00293 // walk down the child chain right away (try the next window first) 00294 // Eventhough we are on a new sibbling chain, we don't update 00295 // pwndSibblingLoop yet; this is because we must walk down this 00296 // child chain again to make sure we visit all the descendents 00297 fAncestor = TRUE; 00298 } 00299 00300 /* Bug 272874 - joejo 00301 * 00302 * Stop infinite loop by only looping a finite number of times and 00303 * then bailing. 00304 */ 00305 } while (nLoopCount++ < 256 * 4); 00306 00307 // It couldn't find one... 00308 return pwndRoot; 00309 } 00310 00311 /***************************************************************************\ 00312 * GetNextDlgTabItem 00313 * 00314 * History: 00315 * 19-Feb-1991 JimA Added access check 00316 \***************************************************************************/ 00317 00318 HWND WINAPI GetNextDlgTabItem( 00319 HWND hwndDlg, 00320 HWND hwnd, 00321 BOOL fPrev) 00322 { 00323 00324 PWND pwnd; 00325 PWND pwndDlg; 00326 PWND pwndNext; 00327 00328 pwndDlg = ValidateHwnd(hwndDlg); 00329 00330 if (pwndDlg == NULL) 00331 return NULL; 00332 00333 if (hwnd != (HWND)0) { 00334 pwnd = ValidateHwnd(hwnd); 00335 00336 if (pwnd == NULL) 00337 return NULL; 00338 00339 } else { 00340 pwnd = (PWND)NULL; 00341 } 00342 00343 pwndNext = _GetNextDlgTabItem(pwndDlg, pwnd, fPrev); 00344 00345 return (HW(pwndNext)); 00346 } 00347 00348 PWND _GetNextDlgTabItem( 00349 PWND pwndDlg, 00350 PWND pwnd, 00351 BOOL fPrev) 00352 { 00353 PWND pwndSave; 00354 00355 if (pwnd == pwndDlg) 00356 pwnd = NULL; 00357 else 00358 { 00359 pwnd = _GetChildControl(pwndDlg, pwnd); 00360 if (pwnd && !_IsDescendant(pwndDlg, pwnd)) 00361 return(NULL); 00362 } 00363 00364 // 00365 // BACKWARD COMPATIBILITY 00366 // 00367 // Note that the result when there are no tabstops of 00368 // IGetNextDlgTabItem(pwndDlg, NULL, FALSE) was the last item, now 00369 // will be the first item. We could put a check for fRecurse here 00370 // and do the old thing if not set. 00371 // 00372 00373 // We are going to bug out if we hit the first child a second time. 00374 00375 pwndSave = pwnd; 00376 00377 pwnd = (fPrev ? _PrevControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) : 00378 _NextControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED)); 00379 00380 if (!pwnd) 00381 goto AllOver; 00382 00383 while ((pwnd != pwndSave) && (pwnd != pwndDlg)) { 00384 UserAssert(pwnd); 00385 00386 if (!pwndSave) 00387 pwndSave = pwnd; 00388 00389 if ((pwnd->style & (WS_TABSTOP | WS_VISIBLE | WS_DISABLED)) == (WS_TABSTOP | WS_VISIBLE)) 00390 // Found it. 00391 break; 00392 00393 pwnd = (fPrev ? _PrevControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) : 00394 _NextControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED)); 00395 } 00396 00397 AllOver: 00398 return pwnd; 00399 } 00400 00401 /***************************************************************************\ 00402 * 00403 * _GetNextDlgGroupItem() 00404 * 00405 \***************************************************************************/ 00406 00407 HWND GetNextDlgGroupItem( 00408 HWND hwndDlg, 00409 HWND hwndCtl, 00410 BOOL bPrevious) 00411 { 00412 PWND pwndDlg; 00413 PWND pwndCtl; 00414 PWND pwndNext; 00415 00416 pwndDlg = ValidateHwnd(hwndDlg); 00417 00418 if (pwndDlg == NULL) 00419 return 0; 00420 00421 00422 if (hwndCtl != (HWND)0) { 00423 pwndCtl = ValidateHwnd(hwndCtl); 00424 00425 if (pwndCtl == NULL) 00426 return 0; 00427 } else { 00428 pwndCtl = (PWND)NULL; 00429 } 00430 00431 if (pwndCtl == pwndDlg) 00432 pwndCtl = pwndDlg; 00433 00434 pwndNext = _GetNextDlgGroupItem(pwndDlg, pwndCtl, bPrevious); 00435 00436 return (HW(pwndNext)); 00437 } 00438 00439 PWND _GetNextDlgGroupItem( 00440 PWND pwndDlg, 00441 PWND pwnd, 00442 BOOL fPrev) 00443 { 00444 PWND pwndCurrent; 00445 BOOL fOnceAround = FALSE; 00446 00447 pwnd = pwndCurrent = _GetChildControl(pwndDlg, pwnd); 00448 00449 do { 00450 pwnd = (fPrev ? UT_PrevGroupItem(pwndDlg, pwnd) : 00451 UT_NextGroupItem(pwndDlg, pwnd)); 00452 00453 if (pwnd == pwndCurrent) 00454 fOnceAround = TRUE; 00455 00456 if (!pwndCurrent) 00457 pwndCurrent = pwnd; 00458 } 00459 while (!fOnceAround && ((TestWF(pwnd, WFDISABLED) || !TestWF(pwnd, WFVISIBLE)))); 00460 00461 return pwnd; 00462 }

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