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.
 
 
 
 
 
 

466 lines
13 KiB

/****************************** Module Header ******************************\
* Module Name: dlgmgrc.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* This module contains client side dialog functionality
*
* History:
* 15-Dec-1993 JohnC Pulled functions from user\server.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* UT_PrevGroupItem
*
* History:
\***************************************************************************/
PWND UT_PrevGroupItem(
PWND pwndDlg,
PWND pwndCurrent)
{
PWND pwnd, pwndPrev;
if (pwndCurrent == NULL || !TestWF(pwndCurrent, WFGROUP))
return _PrevControl(pwndDlg, pwndCurrent, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
pwndPrev = pwndCurrent;
while (TRUE) {
pwnd = _NextControl(pwndDlg, pwndPrev, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
if (TestWF(pwnd, WFGROUP) || pwnd == pwndCurrent)
return pwndPrev;
pwndPrev = pwnd;
}
}
/***************************************************************************\
* UT_NextGroupItem
*
* History:
\***************************************************************************/
PWND UT_NextGroupItem(
PWND pwndDlg,
PWND pwndCurrent)
{
PWND pwnd, pwndNext;
pwnd = _NextControl(pwndDlg, pwndCurrent, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
if (pwndCurrent == NULL || !TestWF(pwnd, WFGROUP))
return pwnd;
pwndNext = pwndCurrent;
while (!TestWF(pwndNext, WFGROUP)) {
pwnd = _PrevControl(pwndDlg, pwndNext, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
if (pwnd == pwndCurrent)
return pwndNext;
pwndNext = pwnd;
}
return pwndNext;
}
/***************************************************************************\
* _PrevControl
*
* History:
\***************************************************************************/
PWND _PrevControl(
PWND pwndRoot,
PWND pwndStart,
UINT uFlags)
{
BOOL fFirstFound;
PWND pwndNext;
PWND pwnd, pwndFirst;
if (!pwndStart)
return(NULL);
UserAssert(pwndRoot != pwndStart);
UserAssert(!TestWF(pwndStart, WEFCONTROLPARENT));
pwnd = _NextControl(pwndRoot, NULL, uFlags);
pwndFirst = pwnd;
fFirstFound = FALSE;
while (pwndNext = _NextControl(pwndRoot, pwnd, uFlags)) {
if (pwndNext == pwndStart)
break;
if (pwndNext == pwndFirst) {
if (fFirstFound) {
RIPMSG0(RIP_WARNING, "_PrevControl: Loop Detected");
break;
} else {
fFirstFound = TRUE;
}
}
pwnd = pwndNext;
}
return pwnd;
}
/***************************************************************************\
*
* GetChildControl()
*
* Gets valid ancestor of given window.
* A valid dialog control is a direct descendant of a "form" control.
*
\***************************************************************************/
PWND _GetChildControl(PWND pwndRoot, PWND pwndChild) {
PWND pwndControl = NULL;
while (pwndChild && TestwndChild(pwndChild) && (pwndChild != pwndRoot)) {
pwndControl = pwndChild;
pwndChild = REBASEPWND(pwndChild, spwndParent);
if (TestWF(pwndChild, WEFCONTROLPARENT))
break;
}
return(pwndControl);
}
/***************************************************************************\
*
* _NextSibblingOrAncestor
*
* Called by _NextControl. It returns the next control to pwndStart. If there
* is a next window (pwndStart->spwndNext), then that is it.
* Otherwise, the next control is up the parent chain. However, if it's already
* at the top of the chain (pwndRoot == pwndStart->spwndParent), then the next
* control is the first child of pwndRoot. But if it's not at the top of the chain,
* then the next control is pwndStart->spwndParent or an ancestor.
*
\***************************************************************************/
PWND _NextSibblingOrAncestor (PWND pwndRoot, PWND pwndStart)
{
PWND pwndParent;
#if DBG
PWND pwndNext;
#endif
// If there is a sibbling, go for it
if (pwndStart->spwndNext != NULL) {
return (REBASEALWAYS(pwndStart, spwndNext));
}
// If it cannot go up the parent chain, then return the first sibbling.
pwndParent = REBASEALWAYS(pwndStart, spwndParent);
if (pwndParent == pwndRoot) {
// Note that if pwndStart doesn't have any sibblings,
// this will return pwndStart again
return (REBASEALWAYS(pwndParent, spwndChild));
}
// Otherwise walk up the parent chain looking for the first window with
// a WS_EX_CONTROLPARENT parent.
#if DBG
pwndNext =
#else
return
#endif
_GetChildControl(pwndRoot, pwndParent);
#if DBG
if ((pwndNext != pwndParent) || !TestWF(pwndParent, WEFCONTROLPARENT)) {
// Code looping through the controls in a dialog might go into an infinite
// loop because of this (i.e., xxxRemoveDefaultButton, _GetNextDlgTabItem,..)
// We've walked up the parent chain but will never walk down the child chain again
// because there is a NON WS_EX_CONTROLPARENT parent window somewhere in the chain.
RIPMSG0 (RIP_ERROR, "_NextSibblingOrAncestor: Non WS_EX_CONTROLPARENT window in parent chain");
}
return pwndNext;
#endif
}
/***************************************************************************\
*
* _NextControl()
*
* It searches for the next NON WS_EX_CONTROLPARENT control following pwndStart.
* If pwndStart is NULL, the search begins with pwndRoot's first child;
* otherwise, it starts with the control next to pwndStart.
* This is a depth-first search that can start anywhere in the window tree.
* uFlags determine what WS_EX_CONTROLPARENT windows should be skipped or recursed into.
* If skipping a window, the search moves to the next control (see _NextSibblingOrAncestor);
* otherwise, the search walks down the child chain (recursive call).
* If the search fails, it returns pwndRoot.
*
\***************************************************************************/
PWND _NextControl(
PWND pwndRoot,
PWND pwndStart,
UINT uFlags)
{
BOOL fSkip, fAncestor;
PWND pwndLast, pwndSibblingLoop;
/* Bug 272874 - joejo
*
* Stop infinite loop by only looping a finite number of times and
* then bailing.
*/
int nLoopCount = 0;
UserAssert (pwndRoot != NULL);
if (pwndStart == NULL) {
// Start with pwndRoot's first child
pwndStart = REBASEPWND(pwndRoot, spwndChild);
pwndLast = pwndStart;
fAncestor = FALSE;
} else {
UserAssert ((pwndRoot != pwndStart) && _IsDescendant(pwndRoot, pwndStart));
// Save starting handle and get next one
pwndLast = pwndStart;
pwndSibblingLoop = pwndStart;
fAncestor = TRUE;
goto TryNextOne;
}
// If no more controls, game over
if (pwndStart == NULL) {
return pwndRoot;
}
// Search for a non WS_EX_CONTROLPARENT window; if a window should be skipped,
// try its spwndNext; otherwise, walk down its child chain.
pwndSibblingLoop = pwndStart;
do {
//If not WS_EX_CONTROLPARENT parent, done.
if (!TestWF(pwndStart, WEFCONTROLPARENT)) {
return pwndStart;
}
// Do they want to skip this window?
fSkip = ((uFlags & CWP_SKIPINVISIBLE) && !TestWF(pwndStart, WFVISIBLE))
|| ((uFlags & CWP_SKIPDISABLED) && TestWF(pwndStart, WFDISABLED));
// Remember the current window
pwndLast = pwndStart;
// Walk down child chain?
if (!fSkip && !fAncestor) {
pwndStart = _NextControl (pwndStart, NULL, uFlags);
// If it found one, done.
if (pwndStart != pwndLast) {
return pwndStart;
}
}
TryNextOne:
// Try the next one.
pwndStart = _NextSibblingOrAncestor (pwndRoot, pwndStart);
if (pwndStart == NULL) {
break;
}
// If parents are the same, we are still in the same sibbling chain
if (pwndLast->spwndParent == pwndStart->spwndParent) {
// If we had just moved up the parent chain last time around,
// mark this as the beginning of the new sibbling chain.
// Otherwise, check if we've looped through all sibblings already.
if (fAncestor) {
// Beggining of new sibbling chain.
pwndSibblingLoop = pwndStart;
} else if (pwndStart == pwndSibblingLoop) {
// Already visited all sibblings, so done.
break;
}
fAncestor = FALSE;
} else {
// We must have moved up the parent chain, so don't
// walk down the child chain right away (try the next window first)
// Eventhough we are on a new sibbling chain, we don't update
// pwndSibblingLoop yet; this is because we must walk down this
// child chain again to make sure we visit all the descendents
fAncestor = TRUE;
}
/* Bug 272874 - joejo
*
* Stop infinite loop by only looping a finite number of times and
* then bailing.
*/
} while (nLoopCount++ < 256 * 4);
// It couldn't find one...
return pwndRoot;
}
/***************************************************************************\
* GetNextDlgTabItem
*
* History:
* 19-Feb-1991 JimA Added access check
\***************************************************************************/
FUNCLOG3(LOG_GENERAL, HWND, WINAPI, GetNextDlgTabItem, HWND, hwndDlg, HWND, hwnd, BOOL, fPrev)
HWND WINAPI GetNextDlgTabItem(
HWND hwndDlg,
HWND hwnd,
BOOL fPrev)
{
PWND pwnd;
PWND pwndDlg;
PWND pwndNext;
pwndDlg = ValidateHwnd(hwndDlg);
if (pwndDlg == NULL)
return NULL;
if (hwnd != (HWND)0) {
pwnd = ValidateHwnd(hwnd);
if (pwnd == NULL)
return NULL;
} else {
pwnd = (PWND)NULL;
}
pwndNext = _GetNextDlgTabItem(pwndDlg, pwnd, fPrev);
return (HW(pwndNext));
}
PWND _GetNextDlgTabItem(
PWND pwndDlg,
PWND pwnd,
BOOL fPrev)
{
PWND pwndSave;
if (pwnd == pwndDlg)
pwnd = NULL;
else
{
pwnd = _GetChildControl(pwndDlg, pwnd);
if (pwnd && !_IsDescendant(pwndDlg, pwnd))
return(NULL);
}
//
// BACKWARD COMPATIBILITY
//
// Note that the result when there are no tabstops of
// IGetNextDlgTabItem(pwndDlg, NULL, FALSE) was the last item, now
// will be the first item. We could put a check for fRecurse here
// and do the old thing if not set.
//
// We are going to bug out if we hit the first child a second time.
pwndSave = pwnd;
pwnd = (fPrev ? _PrevControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) :
_NextControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED));
if (!pwnd)
goto AllOver;
while ((pwnd != pwndSave) && (pwnd != pwndDlg)) {
UserAssert(pwnd);
if (!pwndSave)
pwndSave = pwnd;
if ((pwnd->style & (WS_TABSTOP | WS_VISIBLE | WS_DISABLED)) == (WS_TABSTOP | WS_VISIBLE))
// Found it.
break;
pwnd = (fPrev ? _PrevControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) :
_NextControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED));
}
AllOver:
return pwnd;
}
/***************************************************************************\
*
* _GetNextDlgGroupItem()
*
\***************************************************************************/
FUNCLOG3(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, GetNextDlgGroupItem, HWND, hwndDlg, HWND, hwndCtl, BOOL, bPrevious)
HWND GetNextDlgGroupItem(
HWND hwndDlg,
HWND hwndCtl,
BOOL bPrevious)
{
PWND pwndDlg;
PWND pwndCtl;
PWND pwndNext;
pwndDlg = ValidateHwnd(hwndDlg);
if (pwndDlg == NULL)
return 0;
if (hwndCtl != (HWND)0) {
pwndCtl = ValidateHwnd(hwndCtl);
if (pwndCtl == NULL)
return 0;
} else {
pwndCtl = (PWND)NULL;
}
if (pwndCtl == pwndDlg)
pwndCtl = pwndDlg;
pwndNext = _GetNextDlgGroupItem(pwndDlg, pwndCtl, bPrevious);
return (HW(pwndNext));
}
PWND _GetNextDlgGroupItem(
PWND pwndDlg,
PWND pwnd,
BOOL fPrev)
{
PWND pwndCurrent;
BOOL fOnceAround = FALSE;
pwnd = pwndCurrent = _GetChildControl(pwndDlg, pwnd);
do {
pwnd = (fPrev ? UT_PrevGroupItem(pwndDlg, pwnd) :
UT_NextGroupItem(pwndDlg, pwnd));
if (pwnd == pwndCurrent)
fOnceAround = TRUE;
if (!pwndCurrent)
pwndCurrent = pwnd;
}
while (!fOnceAround && ((TestWF(pwnd, WFDISABLED) || !TestWF(pwnd, WFVISIBLE))));
return pwnd;
}