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.
1450 lines
43 KiB
1450 lines
43 KiB
/***************************************************************************\
|
|
*
|
|
* DLGMGR.C -
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Dialog Box Manager Routines
|
|
*
|
|
* ??-???-???? mikeke Ported from Win 3.0 sources
|
|
* 12-Feb-1991 mikeke Added Revalidation code
|
|
* 19-Feb-1991 JimA Added access checks
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define UNICODE_MINUS_SIGN 0x2212
|
|
|
|
|
|
LOOKASIDE DialogLookaside;
|
|
|
|
BOOL ValidateCallback(HANDLE h);
|
|
|
|
#define IsInForegroundQueue(hwnd) \
|
|
(NtUserQueryWindow(hwnd, WindowIsForegroundThread) != NULL)
|
|
#define IsCurrentThreadForeground() \
|
|
((BOOL)NtUserGetThreadState(UserThreadStateIsForeground))
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* GetParentDialog()
|
|
*
|
|
* Gets top level window, not a control parent. If not a dialog, then use
|
|
* "highest" control parent guy.
|
|
*
|
|
* BOGUS
|
|
* Need a way to mark a window as a dialog. If it ever comes into
|
|
* DefDlgProc(), set an internal flag. Will be used by thunking and
|
|
* CallDlgProc() optimizations also!
|
|
*
|
|
\***************************************************************************/
|
|
|
|
PWND GetParentDialog(PWND pwndDialog)
|
|
{
|
|
PWND pwndParent;
|
|
|
|
pwndParent = pwndDialog;
|
|
|
|
//
|
|
// Walk up the parent chain. We're looking for the top-most dialog
|
|
// window. Most cases, the window is a top level one. But in case of
|
|
// backup app, the window will be a child of some other window.
|
|
//
|
|
for (; pwndDialog; pwndDialog = REBASEPWND(pwndDialog, spwndParent))
|
|
{
|
|
if (TestWF(pwndDialog, WFDIALOGWINDOW))
|
|
{
|
|
//
|
|
// For old guys: If not DS_RECURSE, then stop here.
|
|
// that way old apps which try to do the nested dialog
|
|
// stuff in their old limited way don't die.
|
|
//
|
|
if (TestWF(pwndDialog, WEFCONTROLPARENT))
|
|
pwndParent = pwndDialog;
|
|
else if (!TestWF(pwndDialog, DFCONTROL))
|
|
break;
|
|
}
|
|
|
|
if (!TestWF(pwndDialog, WFCHILD))
|
|
break;
|
|
}
|
|
|
|
return(pwndParent);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxSaveDlgFocus
|
|
*
|
|
* History:
|
|
* 02-18-92 JimA Ported from Win31 sources
|
|
\***************************************************************************/
|
|
|
|
BOOL xxxSaveDlgFocus(
|
|
PWND pwnd)
|
|
{
|
|
HWND hwndFocus = GetFocus();
|
|
|
|
CheckLock(pwnd);
|
|
|
|
if (hwndFocus != NULL && IsChild(HWq(pwnd), hwndFocus) &&
|
|
PDLG(pwnd)->hwndFocusSave == NULL) {
|
|
PDLG(pwnd)->hwndFocusSave = hwndFocus;
|
|
xxxRemoveDefaultButton(pwnd, ValidateHwnd(hwndFocus));
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxRestoreDlgFocus
|
|
*
|
|
* History:
|
|
* 02-18-92 JimA Ported from Win31 sources
|
|
* 01-01-2001 Mohamed Need to re-validate the window before cleanup.
|
|
\***************************************************************************/
|
|
|
|
// LATER
|
|
// 21-Mar-1992 mikeke
|
|
// does pwndFocusSave need to be unlocked when the dialog is destroyed?
|
|
|
|
BOOL xxxRestoreDlgFocus(
|
|
PWND pwnd)
|
|
{
|
|
HWND hwndFocus;
|
|
HWND hwndFocusSave;
|
|
BOOL fRestored = FALSE;
|
|
|
|
CheckLock(pwnd);
|
|
|
|
|
|
if (PDLG(pwnd)->hwndFocusSave && !TestWF(pwnd, WFMINIMIZED)) {
|
|
|
|
hwndFocus = GetFocus();
|
|
hwndFocusSave = KHWND_TO_HWND(PDLG(pwnd)->hwndFocusSave);
|
|
|
|
if (IsWindow(hwndFocusSave)) {
|
|
xxxCheckDefPushButton(pwnd, hwndFocus, hwndFocusSave);
|
|
fRestored = (NtUserSetFocus(hwndFocusSave) != NULL);
|
|
}
|
|
//
|
|
// After calling SetFocus(), we need to re-validate
|
|
// the window. PDLG(pwnd) might be NULL.
|
|
//
|
|
|
|
if (ValidateDialogPwnd(pwnd)) {
|
|
PDLG(pwnd)->hwndFocusSave = NULL;
|
|
}
|
|
}
|
|
|
|
return fRestored;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* DlgSetFocus
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void DlgSetFocus(
|
|
HWND hwnd)
|
|
{
|
|
if (((UINT)SendMessage(hwnd, WM_GETDLGCODE, 0, 0)) & DLGC_HASSETSEL) {
|
|
SendMessage(hwnd, EM_SETSEL, 0, MAXLONG);
|
|
}
|
|
|
|
NtUserSetFocus(hwnd);
|
|
}
|
|
|
|
|
|
|
|
FUNCLOG1(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetDlgCtrlID, HWND, hwnd)
|
|
int GetDlgCtrlID(
|
|
HWND hwnd)
|
|
{
|
|
PWND pwnd;
|
|
|
|
pwnd = ValidateHwnd(hwnd);
|
|
if (pwnd == NULL)
|
|
return 0;
|
|
|
|
return PtrToLong(pwnd->spmenu);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* ValidateDialogPwnd
|
|
*
|
|
* Under Win3, DLGWINDOWEXTRA is 30 bytes. We cannot change that for 16 bit
|
|
* compatibility reasons. Problem is there is no way to tell if a given
|
|
* 16 bit window depends on byte count. If there was, this would be easy.
|
|
* The only way to tell is when a window is about to be used as a dialog
|
|
* window. This window may be of the class DIALOGCLASS, but again it may
|
|
* not!! So we keep dialog window words at 30 bytes, and allocate another
|
|
* structure for the real dialog structure fields. Problem is that this
|
|
* structure has to be created lazily! And that's what we're doing here.
|
|
*
|
|
* 05-21-91 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
BOOL ValidateDialogPwnd(
|
|
PWND pwnd)
|
|
{
|
|
static BOOL sfInit = TRUE;
|
|
PDLG pdlg;
|
|
|
|
/*
|
|
* This bit is set if we've already run through this initialization and
|
|
* have identified this window as a dialog window (able to withstand
|
|
* peeks into window words at random moments in time).
|
|
*/
|
|
if (TestWF(pwnd, WFDIALOGWINDOW))
|
|
return TRUE;
|
|
|
|
if (pwnd->cbwndExtra < DLGWINDOWEXTRA) {
|
|
RIPERR0(ERROR_WINDOW_NOT_DIALOG, RIP_VERBOSE, "");
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* See if the pdlg was destroyed and this is a rogue message to be ignored
|
|
*/
|
|
if (pwnd->fnid & FNID_STATUS_BITS) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* If the lookaside buffer has not been initialized, do it now.
|
|
*/
|
|
if (sfInit) {
|
|
if (!NT_SUCCESS(InitLookaside(&DialogLookaside, sizeof(DLG), 2))) {
|
|
return FALSE;
|
|
}
|
|
sfInit = FALSE;
|
|
}
|
|
|
|
if ((pdlg = (PDLG)AllocLookasideEntry(&DialogLookaside)) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
NtUserCallHwndParam(HWq(pwnd), (ULONG_PTR)pdlg, SFI_SETDIALOGPOINTER);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* CvtDec
|
|
*
|
|
* LATER!!! convert to itoa?
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void CvtDec(
|
|
int u,
|
|
LPWSTR *lplpch)
|
|
{
|
|
if (u >= 10) {
|
|
CvtDec(u / 10, lplpch);
|
|
u %= 10;
|
|
}
|
|
|
|
*(*lplpch)++ = (WCHAR)(u + '0');
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* SetDlgItemInt
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetDlgItemInt, HWND, hwnd, int, item, UINT, u, BOOL, fSigned)
|
|
BOOL SetDlgItemInt(
|
|
HWND hwnd,
|
|
int item,
|
|
UINT u,
|
|
BOOL fSigned)
|
|
{
|
|
LPWSTR lpch;
|
|
WCHAR rgch[16];
|
|
|
|
lpch = rgch;
|
|
if (fSigned) {
|
|
if ((int)u < 0) {
|
|
*lpch++ = TEXT('-');
|
|
u = (UINT)(-(int)u);
|
|
}
|
|
} else {
|
|
if (u & 0x80000000) {
|
|
CvtDec(u / 10, (LPWSTR FAR *)&lpch);
|
|
u = u % 10;
|
|
}
|
|
}
|
|
|
|
CvtDec(u, (LPWSTR FAR *)&lpch);
|
|
*lpch = 0;
|
|
|
|
return SetDlgItemTextW(hwnd, item, rgch);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* CheckDlgButton
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, CheckDlgButton, HWND, hwnd, int, id, UINT, cmdCheck)
|
|
BOOL CheckDlgButton(
|
|
HWND hwnd,
|
|
int id,
|
|
UINT cmdCheck)
|
|
{
|
|
if ((hwnd = GetDlgItem(hwnd, id)) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
SendMessage(hwnd, BM_SETCHECK, cmdCheck, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetDlgItemInt
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
UINT GetDlgItemInt(
|
|
HWND hwnd,
|
|
int item,
|
|
BOOL FAR *lpfValOK,
|
|
BOOL fSigned)
|
|
{
|
|
int i, digit, ch;
|
|
int maxTens, maxUnits;
|
|
BOOL fOk, fNeg;
|
|
LPWSTR lpch;
|
|
WCHAR rgch[48];
|
|
WCHAR rgchDigits[48];
|
|
|
|
fOk = FALSE;
|
|
if (lpfValOK != NULL)
|
|
*lpfValOK = FALSE;
|
|
|
|
if (!GetDlgItemTextW(hwnd, item, rgch, sizeof(rgch)/sizeof(WCHAR) - 1))
|
|
return 0;
|
|
|
|
lpch = rgch;
|
|
|
|
/*
|
|
* Skip leading white space.
|
|
*/
|
|
while (*lpch == TEXT(' '))
|
|
lpch++;
|
|
|
|
fNeg = FALSE;
|
|
while (fSigned && ((*lpch == L'-') || (*lpch == UNICODE_MINUS_SIGN))) {
|
|
lpch++;
|
|
fNeg ^= TRUE;
|
|
}
|
|
|
|
if (fSigned) {
|
|
maxTens = INT_MAX/10;
|
|
maxUnits = INT_MAX%10;
|
|
} else {
|
|
maxTens = UINT_MAX/10;
|
|
maxUnits = UINT_MAX%10;
|
|
}
|
|
/*
|
|
* Convert all decimal digits to ASCII Unicode digits 0x0030 - 0x0039
|
|
*/
|
|
FoldStringW(MAP_FOLDDIGITS, lpch, -1, rgchDigits,
|
|
sizeof(rgchDigits)/sizeof(rgchDigits[0]));
|
|
lpch = rgchDigits;
|
|
|
|
i = 0;
|
|
while (ch = *lpch++) {
|
|
digit = ch - TEXT('0');
|
|
if (digit < 0 || digit > 9) {
|
|
break;
|
|
}
|
|
if ((UINT)i >= (UINT)maxTens) {
|
|
/*
|
|
* We need to special case INT_MIN as the i = -i
|
|
* would damage it
|
|
*/
|
|
if (i == maxTens) {
|
|
if (digit == maxUnits+1 && fNeg && (*lpch) == 0) {
|
|
i = INT_MIN;
|
|
goto HaveResult;
|
|
} else if (digit > maxUnits) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
fOk = TRUE;
|
|
i = ((UINT)i * 10) + digit;
|
|
}
|
|
|
|
if (fNeg)
|
|
i = -i;
|
|
HaveResult:
|
|
if (lpfValOK != NULL)
|
|
*lpfValOK = ((ch == 0) && fOk);
|
|
|
|
return (UINT)i;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CheckRadioButton
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, CheckRadioButton, HWND, hwnd, int, idFirst, int, idLast, int, id)
|
|
BOOL CheckRadioButton(
|
|
HWND hwnd,
|
|
int idFirst,
|
|
int idLast,
|
|
int id)
|
|
{
|
|
PWND pwnd, pwndDialog;
|
|
BOOL fCheckOn;
|
|
|
|
pwndDialog = ValidateHwnd(hwnd);
|
|
if (pwndDialog == NULL)
|
|
return 0;
|
|
|
|
for (pwnd = REBASE(pwndDialog, spwndChild); pwnd; pwnd = REBASE(pwnd, spwndNext)) {
|
|
|
|
if ((PtrToLong(pwnd->spmenu) >= idFirst) &&
|
|
(PtrToLong(pwnd->spmenu) <= idLast)) {
|
|
|
|
fCheckOn = (PtrToLong(pwnd->spmenu) == id);
|
|
SendMessage(PtoHq(pwnd), BM_SETCHECK, fCheckOn, 0L);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* IsDlgButtonChecked
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, IsDlgButtonChecked, HWND, hwnd, int, id)
|
|
UINT IsDlgButtonChecked(
|
|
HWND hwnd,
|
|
int id)
|
|
{
|
|
if ((hwnd = GetDlgItem(hwnd, id)) != NULL) {
|
|
return (UINT)SendMessage(hwnd, BM_GETCHECK, 0, 0);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* DefDlgProc
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
LRESULT DefDlgProcWorker(
|
|
PWND pwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
DWORD fAnsi)
|
|
{
|
|
HWND hwnd = HWq(pwnd);
|
|
TL tlpwndT1, tlpwndT2, tlpwndT3, tlpwndTop;
|
|
PWND pwndT;
|
|
PWND pwndT1, pwndT2, pwndT3, pwndTop;
|
|
HWND hwndT1;
|
|
LRESULT result;
|
|
BOOL fSetBit;
|
|
DLGPROC pfn;
|
|
|
|
CheckLock(pwnd);
|
|
|
|
/*
|
|
* use the Win 3.1 documented size
|
|
*/
|
|
VALIDATECLASSANDSIZE(pwnd, FNID_DIALOG);
|
|
|
|
/*
|
|
* Must do special validation here to make sure pwnd is a dialog window.
|
|
*/
|
|
if (!ValidateDialogPwnd(pwnd))
|
|
return 0;
|
|
|
|
if (((PDIALOG)pwnd)->resultWP != 0)
|
|
NtUserSetWindowLongPtr(hwnd, DWLP_MSGRESULT, 0, FALSE);
|
|
result = 0; // no dialog proc
|
|
|
|
if (message == WM_FINALDESTROY) {
|
|
goto DoCleanup;
|
|
}
|
|
|
|
if ((pfn = PDLG(pwnd)->lpfnDlg) != NULL) {
|
|
/* Bug 234292 - joejo
|
|
* Since the called window/dialog proc may have a different calling
|
|
* convention, we must wrap the call and, check esp and replace with
|
|
* a good esp when the call returns. This is what UserCallWinProc* does.
|
|
*/
|
|
if (UserCallDlgProcCheckWow(pwnd->pActCtx, pfn, hwnd, message, wParam, lParam, &(pwnd->state), &result)) {
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Get out if the window was destroyed in the dialog proc.
|
|
*/
|
|
if ((RevalidateHwnd(hwnd)==NULL) || (pwnd->fnid & FNID_STATUS_BITS))
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* SPECIAL CASED ... and DOCUMENTED that way !!!
|
|
* These 6, and ONLY these 6, should be hacked in this fashion.
|
|
* Anybody who needs the REAL return value to a message should
|
|
* use SetDlgMsgResult in WINDOWSX.H
|
|
*/
|
|
|
|
switch (message)
|
|
{
|
|
case WM_COMPAREITEM:
|
|
case WM_VKEYTOITEM:
|
|
case WM_CHARTOITEM:
|
|
case WM_INITDIALOG:
|
|
case WM_QUERYDRAGICON:
|
|
return ((LRESULT)(DWORD)result);
|
|
|
|
case WM_CTLCOLOR:
|
|
case WM_CTLCOLORMSGBOX:
|
|
case WM_CTLCOLOREDIT:
|
|
case WM_CTLCOLORLISTBOX:
|
|
case WM_CTLCOLORBTN:
|
|
case WM_CTLCOLORDLG:
|
|
case WM_CTLCOLORSCROLLBAR:
|
|
case WM_CTLCOLORSTATIC:
|
|
// QuarkXPress doesn't like finding the WM_CTLCOLOR result in
|
|
// resultWP -- we should never be setting resultWP -- that's meant
|
|
// as a pass-thru return value -- so let's go back to doing it the
|
|
// old way -- Win95B B#21269 -- 03/13/95 -- tracysh (cr: jeffbog)
|
|
if (result)
|
|
return result;
|
|
break;
|
|
}
|
|
|
|
if (!result) {
|
|
|
|
/*
|
|
* Save the result value in case our private memory is freed
|
|
* before we return
|
|
*/
|
|
// result = PDLG(pwnd)->resultWP;
|
|
|
|
switch (message) {
|
|
case WM_CTLCOLOR:
|
|
case WM_CTLCOLORMSGBOX:
|
|
case WM_CTLCOLOREDIT:
|
|
case WM_CTLCOLORLISTBOX:
|
|
case WM_CTLCOLORBTN:
|
|
case WM_CTLCOLORDLG:
|
|
case WM_CTLCOLORSCROLLBAR:
|
|
case WM_CTLCOLORSTATIC:
|
|
{
|
|
//
|
|
// HACK OF DEATH:
|
|
// To get 3D colors for non 4.0 apps who use 3DLOOK,
|
|
// we temporarily add on the 4.0 compat bit, pass this
|
|
// down to DWP, and clear it.
|
|
//
|
|
// Use "result" var for bool saying we have to add/clear 4.0
|
|
// compat bit.
|
|
|
|
fSetBit = (TestWF(pwnd, DF3DLOOK)!= 0) &&
|
|
(TestWF(pwnd, WFWIN40COMPAT) == 0);
|
|
|
|
if (fSetBit)
|
|
SetWindowState(pwnd, WFWIN40COMPAT);
|
|
|
|
result = DefWindowProcWorker(pwnd, message,
|
|
wParam, lParam, fAnsi);
|
|
|
|
if (fSetBit)
|
|
ClearWindowState(pwnd, WFWIN40COMPAT);
|
|
return result;
|
|
}
|
|
|
|
case WM_ERASEBKGND:
|
|
FillWindow(hwnd, hwnd, (HDC)wParam, (HBRUSH)CTLCOLOR_DLG);
|
|
return TRUE;
|
|
|
|
case WM_SHOWWINDOW:
|
|
|
|
/*
|
|
* If hiding the window, save the focus. If showing the window
|
|
* by means of a SW_* command and the fEnd bit is set, do not
|
|
* pass to DWP so it won't get shown.
|
|
*/
|
|
if (GetParentDialog(pwnd) == pwnd) {
|
|
if (!wParam) {
|
|
xxxSaveDlgFocus(pwnd);
|
|
} else {
|
|
|
|
if (LOWORD(lParam) != 0 && PDLG(pwnd)->fEnd)
|
|
break;
|
|
|
|
/*
|
|
* Snap the cursor to the center of the default button.
|
|
* Only do this if the current thread is in the foreground.
|
|
* The _ShowCursor() code is added to work around a
|
|
* problem with hardware cursors. If change is done
|
|
* in the same refresh cycle, the display of the cursor
|
|
* would not reflect the new position.
|
|
*/
|
|
if (TEST_PUSIF(PUSIF_SNAPTO) &&
|
|
IsInForegroundQueue(hwnd)) {
|
|
hwndT1 = GetDlgItem(hwnd, (int)PDLG(pwnd)->result);
|
|
if (hwndT1) {
|
|
RECT rc;
|
|
|
|
NtUserShowCursor(FALSE);
|
|
|
|
GetWindowRect(hwndT1, &rc);
|
|
NtUserSetCursorPos(rc.left + ((rc.right - rc.left)/2),
|
|
rc.top + ((rc.bottom - rc.top)/2));
|
|
|
|
NtUserShowCursor(TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto CallDWP;
|
|
|
|
case WM_SYSCOMMAND:
|
|
if (GetParentDialog(pwnd) == pwnd) {
|
|
/*
|
|
* If hiding the window, save the focus. If showing the window
|
|
* by means of a SW_* command and the fEnd bit is set, do not
|
|
* pass to DWP so it won't get shown.
|
|
*/
|
|
if ((int)wParam == SC_MINIMIZE)
|
|
xxxSaveDlgFocus(pwnd);
|
|
}
|
|
goto CallDWP;
|
|
|
|
case WM_ACTIVATE:
|
|
pwndT1 = GetParentDialog(pwnd);
|
|
if ( pwndT1 != pwnd) {
|
|
|
|
/*
|
|
* This random bit is used during key processing - bit
|
|
* 08000000 of WM_CHAR messages is set if a dialog is currently
|
|
* active.
|
|
*/
|
|
NtUserSetThreadState(wParam ? QF_DIALOGACTIVE : 0, QF_DIALOGACTIVE);
|
|
}
|
|
|
|
ThreadLock(pwndT1, &tlpwndT1);
|
|
if (wParam != 0)
|
|
xxxRestoreDlgFocus(pwndT1);
|
|
else
|
|
xxxSaveDlgFocus(pwndT1);
|
|
|
|
ThreadUnlock(&tlpwndT1);
|
|
break;
|
|
|
|
case WM_SETFOCUS:
|
|
pwndT1 = GetParentDialog(pwnd);
|
|
if (!PDLG(pwndT1)->fEnd && !xxxRestoreDlgFocus(pwndT1)) {
|
|
|
|
pwndT = _GetNextDlgTabItem(pwndT1, NULL, FALSE);
|
|
DlgSetFocus(HW(pwndT));
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
/*
|
|
* Make sure cancel button is not disabled before sending the
|
|
* IDCANCEL. Note that we need to do this as a message instead
|
|
* of directly calling the dlg proc so that any dialog box
|
|
* filters get this.
|
|
*/
|
|
pwndT1 = _GetDlgItem(pwnd, IDCANCEL);
|
|
if (pwndT1 && TestWF(pwndT1, WFDISABLED))
|
|
NtUserMessageBeep(0);
|
|
else
|
|
PostMessage(hwnd, WM_COMMAND, MAKELONG(IDCANCEL, BN_CLICKED),
|
|
(LPARAM)HW(pwndT1));
|
|
break;
|
|
|
|
case WM_NCDESTROY:
|
|
case WM_FINALDESTROY:
|
|
DoCleanup:
|
|
NtUserSetThreadState(0, QF_DIALOGACTIVE);
|
|
if (!(pwnd->style & DS_LOCALEDIT)) {
|
|
if (PDLG(pwnd)->hData) {
|
|
ReleaseEditDS(KHANDLE_TO_HANDLE(PDLG(pwnd)->hData));
|
|
PDLG(pwnd)->hData = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Delete the user defined font if any
|
|
*/
|
|
if (PDLG(pwnd)->hUserFont) {
|
|
DeleteObject(KHFONT_TO_HFONT(PDLG(pwnd)->hUserFont));
|
|
PDLG(pwnd)->hUserFont = NULL;
|
|
}
|
|
|
|
/*
|
|
* Free the dialog memory and mark this as a non-dialog window
|
|
*/
|
|
FreeLookasideEntry(&DialogLookaside, KPVOID_TO_PVOID(PDLG(pwnd)));
|
|
NtUserCallHwndParam(hwnd, 0, SFI_SETDIALOGPOINTER);
|
|
break;
|
|
|
|
case DM_REPOSITION:
|
|
{
|
|
RECT rc;
|
|
PMONITOR pMonitor;
|
|
|
|
// DAT recorder APP sends it's own private message 0x402
|
|
// through and we mistake it to be DM_REPOSITION. To avoid
|
|
// this confusion, we do the following check.
|
|
// Fix for Bug#25747 -- 9/29/94 --
|
|
if (!TestWF(pwnd, WEFCONTROLPARENT) ||
|
|
(GETFNID(pwnd) != FNID_DESKTOP &&
|
|
GETFNID(REBASEPWND(pwnd, spwndParent)) != FNID_DESKTOP)) {
|
|
|
|
goto CallDWP;
|
|
}
|
|
|
|
CopyRect(&rc, KPRECT_TO_PRECT(&pwnd->rcWindow));
|
|
pMonitor = _MonitorFromRect(&rc, MONITOR_DEFAULTTOPRIMARY);
|
|
RepositionRect(pMonitor, &rc, pwnd->style, pwnd->ExStyle);
|
|
NtUserSetWindowPos(hwnd, HWND_TOP, rc.left, rc.top,
|
|
rc.right-rc.left, rc.bottom-rc.top,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
}
|
|
break;
|
|
|
|
case DM_SETDEFID:
|
|
pwndT1 = GetParentDialog(pwnd);
|
|
ThreadLock(pwndT1, &tlpwndT1);
|
|
|
|
if (!(PDLG(pwndT1)->fEnd)) {
|
|
|
|
pwndT2 = NULL;
|
|
if (PDLG(pwndT1)->result != 0)
|
|
pwndT2 = _FindDlgItem(pwndT1, (int)PDLG(pwndT1)->result);
|
|
|
|
pwndT3 = NULL;
|
|
if (wParam != 0) {
|
|
pwndT3 = _GetDlgItem(pwnd, (UINT)wParam);
|
|
}
|
|
|
|
ThreadLock(pwndT2, &tlpwndT2);
|
|
ThreadLock(pwndT3, &tlpwndT3);
|
|
|
|
xxxCheckDefPushButton(pwndT1, HW(pwndT2), HW(pwndT3));
|
|
|
|
ThreadUnlock(&tlpwndT3);
|
|
ThreadUnlock(&tlpwndT2);
|
|
|
|
PDLG(pwndT1)->result = (UINT)wParam;
|
|
// if (PDLG(pwnd)->spwndFocusSave) {
|
|
// Lock(&(PDLG(pwnd)->spwndFocusSave), pwndT2);
|
|
// }
|
|
|
|
NotifyWinEvent(EVENT_OBJECT_DEFACTIONCHANGE, HW(pwndT1), OBJID_CLIENT, INDEXID_CONTAINER);
|
|
}
|
|
ThreadUnlock(&tlpwndT1);
|
|
return TRUE;
|
|
|
|
case DM_GETDEFID:
|
|
pwndT1 = GetParentDialog(pwnd);
|
|
|
|
if (!PDLG(pwndT1)->fEnd && PDLG(pwndT1)->result)
|
|
return(MAKELONG(PDLG(pwndT1)->result, DC_HASDEFID));
|
|
else
|
|
return 0;
|
|
break;
|
|
|
|
/*
|
|
* This message was added so that user defined controls that want
|
|
* tab keys can pass the tab off to the next/previous control in the
|
|
* dialog box. Without this, all they could do was set the focus
|
|
* which didn't do the default button stuff.
|
|
*/
|
|
case WM_NEXTDLGCTL:
|
|
pwndTop = GetParentDialog(pwnd);
|
|
ThreadLock(pwndTop, &tlpwndTop);
|
|
|
|
hwndT1 = GetFocus();
|
|
pwndT2 = ValidateHwndNoRip(hwndT1);
|
|
if (LOWORD(lParam)) {
|
|
if (pwndT2 == NULL)
|
|
pwndT2 = pwndTop;
|
|
|
|
/*
|
|
* wParam contains the pwnd of the ctl to set focus to.
|
|
*/
|
|
if ((pwndT1 = ValidateHwnd((HWND)wParam)) == NULL) {
|
|
ThreadUnlock(&tlpwndTop);
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
if (pwndT2 == NULL) {
|
|
|
|
/*
|
|
* Set focus to the first tab item.
|
|
*/
|
|
pwndT1 = _GetNextDlgTabItem(pwndTop, NULL, FALSE);
|
|
pwndT2 = pwndTop;
|
|
} else {
|
|
|
|
/*
|
|
* If window with focus not a dlg ctl, ignore message.
|
|
*/
|
|
if (!_IsChild(pwndTop, pwndT2)) {
|
|
ThreadUnlock(&tlpwndTop);
|
|
return TRUE;
|
|
}
|
|
/*
|
|
* wParam = TRUE for previous, FALSE for next
|
|
*/
|
|
pwndT1 = _GetNextDlgTabItem(pwndTop, pwndT2, (wParam != 0));
|
|
|
|
/*
|
|
* If there is no next item, ignore the message.
|
|
*/
|
|
if (pwndT1 == NULL) {
|
|
ThreadUnlock(&tlpwndTop);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
ThreadLock(pwndT1, &tlpwndT1);
|
|
ThreadLock(pwndT2, &tlpwndT2);
|
|
|
|
DlgSetFocus(HW(pwndT1));
|
|
xxxCheckDefPushButton(pwndTop, HW(pwndT2), HW(pwndT1));
|
|
|
|
ThreadUnlock(&tlpwndT2);
|
|
ThreadUnlock(&tlpwndT1);
|
|
ThreadUnlock(&tlpwndTop);
|
|
|
|
return TRUE;
|
|
|
|
case WM_ENTERMENULOOP:
|
|
|
|
/*
|
|
* We need to pop up the combo box window if the user brings
|
|
* down a menu.
|
|
*
|
|
* ... FALL THROUGH...
|
|
*/
|
|
|
|
case WM_LBUTTONDOWN:
|
|
case WM_NCLBUTTONDOWN:
|
|
hwndT1 = GetFocus();
|
|
if (hwndT1 != NULL) {
|
|
pwndT1 = ValidateHwndNoRip(hwndT1);
|
|
|
|
if (GETFNID(pwndT1) == FNID_COMBOBOX) {
|
|
|
|
/*
|
|
* If user clicks anywhere in dialog box and a combo box (or
|
|
* the editcontrol of a combo box) has the focus, then hide
|
|
* it's listbox.
|
|
*/
|
|
ThreadLockAlways(pwndT1, &tlpwndT1);
|
|
SendMessage(HWq(pwndT1), CB_SHOWDROPDOWN, FALSE, 0);
|
|
ThreadUnlock(&tlpwndT1);
|
|
|
|
} else {
|
|
PWND pwndParent;
|
|
|
|
/*
|
|
* It's a subclassed combo box. See if the listbox and edit
|
|
* boxes exist (this is a very cheezy evaluation - what if
|
|
* these controls are subclassed too? NOTE: Not checking
|
|
* for EditWndProc: it's a client proc address.
|
|
*/
|
|
pwndParent = REBASEPWND(pwndT1, spwndParent);
|
|
if (GETFNID(pwndParent) == FNID_COMBOBOX) {
|
|
pwndT1 = pwndParent;
|
|
ThreadLock(pwndT1, &tlpwndT1);
|
|
SendMessage(HWq(pwndT1), CB_SHOWDROPDOWN, FALSE, 0);
|
|
ThreadUnlock(&tlpwndT1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Always send the message off to DefWndProc
|
|
*/
|
|
goto CallDWP;
|
|
|
|
case WM_GETFONT:
|
|
return (LRESULT)PDLG(pwnd)->hUserFont;
|
|
|
|
case WM_VKEYTOITEM:
|
|
case WM_COMPAREITEM:
|
|
case WM_CHARTOITEM:
|
|
case WM_INITDIALOG:
|
|
|
|
/*
|
|
* We need to return the 0 the app may have returned for these
|
|
* items instead of calling defwindow proc.
|
|
*/
|
|
return result;
|
|
|
|
case WM_NOTIFYFORMAT:
|
|
if (lParam == NF_QUERY)
|
|
return((PDLG(pwnd)->flags & DLGF_ANSI ) ? NFR_ANSI : NFR_UNICODE);
|
|
return result;
|
|
|
|
case WM_INPUTLANGCHANGEREQUEST:
|
|
if (IS_IME_ENABLED()) {
|
|
/*
|
|
* #115190
|
|
* For dialogbox itself, buttons/static controls on top of
|
|
* dialogbox, we'll simply discard this message. B#3843-win95c
|
|
*/
|
|
break;
|
|
}
|
|
if (PDLG(pwnd)->lpfnDlg == MB_DlgProc) {
|
|
break;
|
|
}
|
|
goto CallDWP;
|
|
|
|
default:
|
|
CallDWP:
|
|
return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
|
|
}
|
|
} else if ((message == WM_SHOWWINDOW) && result) {
|
|
|
|
/*
|
|
* For a visible-case we want to snap the cursor regardless of
|
|
* what was returned from the dialog-handler on the client. If
|
|
* we're going visible, snap the cursor to the dialog-button.
|
|
*/
|
|
if (GetParentDialog(pwnd) == pwnd) {
|
|
|
|
if (wParam && ((LOWORD(lParam) == 0) || !PDLG(pwnd)->fEnd)) {
|
|
|
|
/*
|
|
* Snap the cursor to the center of the default button.
|
|
* Only do this if the current thread is in the foreground.
|
|
* The _ShowCursor() code is added to work around a
|
|
* problem with hardware cursors. If change is done
|
|
* in the same refresh cycle, the display of the cursor
|
|
* would not reflect the new position.
|
|
*/
|
|
if (TEST_PUSIF(PUSIF_SNAPTO) &&
|
|
IsInForegroundQueue(hwnd)) {
|
|
hwndT1 = GetDlgItem(hwnd, (int)PDLG(pwnd)->result);
|
|
if (hwndT1) {
|
|
RECT rc;
|
|
|
|
NtUserShowCursor(FALSE);
|
|
|
|
GetWindowRect(hwndT1, &rc);
|
|
NtUserSetCursorPos(rc.left + ((rc.right - rc.left)/2),
|
|
rc.top + ((rc.bottom - rc.top)/2));
|
|
|
|
NtUserShowCursor(TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* If this is still marked as a dialog window then return the real
|
|
* result. Otherwise, we've already processed the WM_NCDESTROY message
|
|
* and freed our private memory so return the stored value.
|
|
*/
|
|
if (TestWF(pwnd, WFDIALOGWINDOW))
|
|
return KERNEL_LRESULT_TO_LRESULT(((PDIALOG)pwnd)->resultWP);
|
|
else
|
|
return result;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* DefDlgProc
|
|
*
|
|
* Translates the message, calls DefDlgProc on server side. DefDlgProc
|
|
* is the default WindowProc for dialogs (NOT the dialog's dialog proc)
|
|
*
|
|
* 04-11-91 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, DefDlgProcW, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam)
|
|
LRESULT WINAPI DefDlgProcW(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PWND pwnd;
|
|
|
|
if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
|
|
return (0L);
|
|
}
|
|
|
|
return DefDlgProcWorker(pwnd, message, wParam, lParam, FALSE);
|
|
}
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, DefDlgProcA, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam)
|
|
LRESULT WINAPI DefDlgProcA(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PWND pwnd;
|
|
|
|
if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
|
|
return (0L);
|
|
}
|
|
|
|
return DefDlgProcWorker(pwnd, message, wParam, lParam, TRUE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* DialogBox2
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
INT_PTR DialogBox2(
|
|
HWND hwnd,
|
|
HWND hwndOwner,
|
|
BOOL fDisabled,
|
|
BOOL fOwnerIsActiveWindow)
|
|
{
|
|
MSG msg;
|
|
INT_PTR result;
|
|
BOOL fShown;
|
|
BOOL fWantIdleMsgs;
|
|
BOOL fSentIdleMessage = FALSE;
|
|
HWND hwndCapture;
|
|
PWND pwnd;
|
|
|
|
if (hwnd) {
|
|
pwnd = ValidateHwnd(hwnd);
|
|
} else {
|
|
pwnd = NULL;
|
|
}
|
|
|
|
CheckLock(pwnd);
|
|
|
|
if (pwnd == NULL) {
|
|
if ((hwndOwner != NULL) && !fDisabled && IsWindow(hwndOwner)) {
|
|
NtUserEnableWindow(hwndOwner, TRUE);
|
|
if (fOwnerIsActiveWindow) {
|
|
|
|
/*
|
|
* The dialog box failed but we disabled the owner in
|
|
* xxxDialogBoxIndirectParam and if it had the focus, the
|
|
* focus was set to NULL. Now, when we enable the window, it
|
|
* doesn't get the focus back if it had it previously so we
|
|
* need to correct this.
|
|
*/
|
|
NtUserSetFocus(hwndOwner);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
hwndCapture = GetCapture();
|
|
if (hwndCapture != NULL) {
|
|
SendMessage(hwndCapture, WM_CANCELMODE, 0, 0);
|
|
}
|
|
|
|
/*
|
|
* Set the 'parent disabled' flag for EndDialog().
|
|
* convert BOOL to definite bit 0 or 1
|
|
*/
|
|
PDLG(pwnd)->fDisabled = !!fDisabled;
|
|
|
|
fShown = TestWF(pwnd, WFVISIBLE);
|
|
|
|
/*
|
|
* Should the WM_ENTERIDLE messages be sent?
|
|
*/
|
|
fWantIdleMsgs = !(pwnd->style & DS_NOIDLEMSG);
|
|
|
|
if ((SYSMET(SLOWMACHINE) & 1) && !fShown && !PDLG(pwnd)->fEnd)
|
|
goto ShowIt;
|
|
|
|
while (PDLG(pwnd) && (!PDLG(pwnd)->fEnd)) {
|
|
if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
ShowIt:
|
|
if (!fShown) {
|
|
fShown = TRUE;
|
|
|
|
#ifdef SYSMODALWINDOWS
|
|
if (pwnd == gspwndSysModal) {
|
|
/*
|
|
* Make this a topmost window
|
|
*/
|
|
NtUserSetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
|
|
SWP_NOSIZE | SWP_NOMOVE |
|
|
SWP_NOREDRAW | SWP_NOACTIVATE);
|
|
}
|
|
#endif
|
|
|
|
NtUserShowWindow(hwnd, SHOW_OPENWINDOW);
|
|
UpdateWindow(hwnd);
|
|
|
|
NotifyWinEvent(EVENT_SYSTEM_DIALOGSTART, hwnd, OBJID_WINDOW, INDEXID_CONTAINER);
|
|
} else {
|
|
/*
|
|
* Make sure window still exists
|
|
*/
|
|
if (hwndOwner && !IsWindow(hwndOwner))
|
|
hwndOwner = NULL;
|
|
|
|
if (hwndOwner && fWantIdleMsgs && !fSentIdleMessage) {
|
|
fSentIdleMessage = TRUE;
|
|
|
|
SendMessage(hwndOwner, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)hwnd);
|
|
} else {
|
|
if ((RevalidateHwnd(hwnd)==NULL) || (pwnd->fnid & FNID_STATUS_BITS))
|
|
break;
|
|
|
|
NtUserWaitMessage();
|
|
}
|
|
}
|
|
|
|
} else {
|
|
/*
|
|
* We got a real message. Reset fSentIdleMessage so that we send
|
|
* one next time things are calm.
|
|
*/
|
|
fSentIdleMessage = FALSE;
|
|
|
|
if (msg.message == WM_QUIT) {
|
|
PostQuitMessage((int)msg.wParam);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If pwnd is a message box, allow Ctrl-C and Ctrl-Ins
|
|
* to copy its content to the clipboard.
|
|
* Fall through in case hooking apps look for these keys.
|
|
*/
|
|
if (TestWF(pwnd, WFMSGBOX)) {
|
|
if ( (msg.message == WM_CHAR && LOBYTE(msg.wParam) == 3) ||
|
|
(msg.message == WM_KEYDOWN && LOBYTE(msg.wParam) == VK_INSERT && GetKeyState(VK_CONTROL) < 0)) {
|
|
/*
|
|
* Send the WM_COPY message and let the original message fall through
|
|
* as some apps might want it
|
|
*/
|
|
SendMessage(hwnd, WM_COPY, 0, 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Moved the msg filter hook call to IsDialogMessage to allow
|
|
* messages to be hooked for both modal and modeless dialog
|
|
* boxes.
|
|
*/
|
|
if (!IsDialogMessage(hwnd, &msg)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
/*
|
|
* If we get a timer message, go ahead and show the window.
|
|
* We may continuously get timer msgs if there are zillions of
|
|
* apps running.
|
|
*
|
|
* If we get a syskeydown message, show the dialog box because
|
|
* the user may be bringing down a menu and we want the dialog
|
|
* box to become visible.
|
|
*/
|
|
if (!fShown && (msg.message == WM_TIMER ||
|
|
msg.message == WM_SYSTIMER || msg.message == WM_SYSKEYDOWN))
|
|
goto ShowIt;
|
|
}
|
|
|
|
if (!RevalidateHwnd(hwnd)) {
|
|
/*
|
|
* Bogus case - we've already been destroyed somehow (by app,
|
|
* GP, etc.)
|
|
*/
|
|
RIPMSG0(RIP_WARNING,
|
|
"Dialog should be dismissed with EndDialog, not DestroyWindow");
|
|
break;
|
|
}
|
|
}
|
|
|
|
NotifyWinEvent(EVENT_SYSTEM_DIALOGEND, hwnd, OBJID_WINDOW, INDEXID_CONTAINER);
|
|
|
|
/*
|
|
* Make sure the window still exists
|
|
*/
|
|
if (!RevalidateHwnd(hwnd)) {
|
|
return 0;
|
|
}
|
|
|
|
if (PDLG(pwnd))
|
|
result = KERNEL_INT_PTR_TO_INT_PTR(PDLG(pwnd)->result);
|
|
else
|
|
result = 0;
|
|
|
|
NtUserDestroyWindow(hwnd);
|
|
|
|
/*
|
|
* If the owner window belongs to another thread, the reactivation
|
|
* of the owner may have failed within DestroyWindow(). Therefore,
|
|
* if the current thread is in the foreground and the owner is not
|
|
* in the foreground we can safely set the foreground back
|
|
* to the owner.
|
|
*/
|
|
if (hwndOwner != NULL) {
|
|
if (IsCurrentThreadForeground() &&
|
|
!IsInForegroundQueue(hwndOwner)) {
|
|
NtUserSetForegroundWindow(hwndOwner);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* InternalDialogBox
|
|
*
|
|
* Server portion of DialogBoxIndirectParam.
|
|
*
|
|
* 04-05-91 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
INT_PTR InternalDialogBox(
|
|
HANDLE hModule,
|
|
LPDLGTEMPLATE lpdt,
|
|
HWND hwndOwner,
|
|
DLGPROC pfnDialog,
|
|
LPARAM lParam,
|
|
UINT fSCDLGFlags)
|
|
{
|
|
INT_PTR i;
|
|
BOOL fDisabled = FALSE;
|
|
HWND hwnd;
|
|
PWND pwndOwner;
|
|
BOOL fOwnerIsActiveWindow = FALSE;
|
|
TL tlpwndOwner;
|
|
BOOL fUnlockOwner;
|
|
|
|
UserAssert(!(fSCDLGFlags & ~(SCDLG_CLIENT|SCDLG_ANSI|SCDLG_16BIT))); // These are the only valid flags
|
|
|
|
/*
|
|
* If hwndOwner == HWNDESKTOP, change it to NULL. This way the desktop
|
|
* (and all its children) won't be disabled if the dialog is modal.
|
|
*/
|
|
if (hwndOwner && SAMEWOWHANDLE(hwndOwner, GetDesktopWindow()))
|
|
hwndOwner = NULL;
|
|
|
|
/*
|
|
* We return 0 if the ValidateHwnd fails in order to match Win 3.1
|
|
* validation layer which always returns 0 for invalid hwnds even
|
|
* if the function is spec'ed to return -1. Autocad setup bug #3615
|
|
*/
|
|
if (hwndOwner) {
|
|
if ((pwndOwner = ValidateHwnd(hwndOwner)) == NULL) {
|
|
return (0L);
|
|
}
|
|
} else {
|
|
pwndOwner = NULL;
|
|
}
|
|
|
|
CheckLock(pwndOwner);
|
|
|
|
fUnlockOwner = FALSE;
|
|
if (pwndOwner != NULL) {
|
|
|
|
/* The following fixes an AV in Corel Photo-Paint 6.0. It passes a
|
|
* 16-bit HWND in, and croaks at some point when it gets 16-bit hwnds
|
|
* back in send messages. FritzS -- fixing bug 12531
|
|
*/
|
|
hwndOwner = PtoHq(pwndOwner);
|
|
|
|
/*
|
|
* Make sure the owner is a top level window.
|
|
*/
|
|
if (TestwndChild(pwndOwner)) {
|
|
pwndOwner = GetTopLevelWindow(pwndOwner);
|
|
hwndOwner = HWq(pwndOwner);
|
|
ThreadLock(pwndOwner, &tlpwndOwner);
|
|
fUnlockOwner = TRUE;
|
|
}
|
|
|
|
/*
|
|
* Remember if window was originally disabled (so we can set
|
|
* the correct state when the dialog goes away.
|
|
*/
|
|
fDisabled = TestWF(pwndOwner, WFDISABLED);
|
|
fOwnerIsActiveWindow = (SAMEWOWHANDLE(hwndOwner, GetActiveWindow()));
|
|
|
|
/*
|
|
* Disable the window.
|
|
*/
|
|
NtUserEnableWindow(hwndOwner, FALSE);
|
|
}
|
|
|
|
/*
|
|
* Don't show cursors on a mouseless system. Put up an hour glass while
|
|
* the dialog comes up.
|
|
*/
|
|
if (SYSMET(MOUSEPRESENT)) {
|
|
NtUserSetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
}
|
|
|
|
/*
|
|
* Creates the dialog. Frees the menu if this routine fails.
|
|
*/
|
|
hwnd = InternalCreateDialog(hModule, lpdt, 0, hwndOwner,
|
|
pfnDialog, lParam, fSCDLGFlags);
|
|
|
|
if (hwnd == NULL) {
|
|
|
|
/*
|
|
* The dialog creation failed. Re-enable the window, destroy the
|
|
* menu, ie., fail gracefully.
|
|
*/
|
|
if (!fDisabled && hwndOwner != NULL)
|
|
NtUserEnableWindow(hwndOwner, TRUE);
|
|
|
|
if (fUnlockOwner)
|
|
ThreadUnlock(&tlpwndOwner);
|
|
return -1;
|
|
}
|
|
|
|
i = DialogBox2(hwnd, hwndOwner, fDisabled, fOwnerIsActiveWindow);
|
|
|
|
if (fUnlockOwner)
|
|
ThreadUnlock(&tlpwndOwner);
|
|
return i;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
**
|
|
** RepositionRect()
|
|
**
|
|
** Used to ensure that toplevel dialogs are still visible within the
|
|
** desktop area after they've resized.
|
|
**
|
|
\***************************************************************************/
|
|
|
|
void
|
|
RepositionRect(
|
|
PMONITOR pMonitor,
|
|
LPRECT lprc,
|
|
DWORD dwStyle,
|
|
DWORD dwExStyle)
|
|
{
|
|
LPRECT lprcClip;
|
|
int y;
|
|
|
|
UserAssert(lprc);
|
|
UserAssert(pMonitor);
|
|
|
|
if (dwStyle & WS_CHILD) {
|
|
if (dwExStyle & WS_EX_CONTROLPARENT)
|
|
return;
|
|
|
|
/*
|
|
* Old style 3.1 child dialogs--do this nonsense anyway. Keeps
|
|
* FedEx happy.
|
|
*/
|
|
pMonitor = GetPrimaryMonitor();
|
|
lprcClip = KPRECT_TO_PRECT(&pMonitor->rcMonitor);
|
|
} else if (dwExStyle & WS_EX_TOOLWINDOW) {
|
|
lprcClip = KPRECT_TO_PRECT(&pMonitor->rcMonitor);
|
|
} else {
|
|
lprcClip = KPRECT_TO_PRECT(&pMonitor->rcWork);
|
|
}
|
|
|
|
UserAssert(lprc);
|
|
|
|
y = lprcClip->bottom - (SYSMET(CYEDGE) * 2 + SYSMET(CYKANJIWINDOW));
|
|
|
|
if (lprc->bottom > y) {
|
|
OffsetRect(lprc, 0, y - lprc->bottom);
|
|
}
|
|
|
|
if (lprc->top < lprcClip->top) {
|
|
OffsetRect(lprc, 0, lprcClip->top - lprc->top);
|
|
}
|
|
|
|
if (lprc->right > lprcClip->right) {
|
|
OffsetRect(lprc, lprcClip->right - lprc->right, 0);
|
|
}
|
|
|
|
if (lprc->left < lprcClip->left) {
|
|
OffsetRect(lprc, lprcClip->left - lprc->left, 0);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* MapDialogRect
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, MapDialogRect, HWND, hwnd, LPRECT, lprc)
|
|
BOOL MapDialogRect(
|
|
HWND hwnd,
|
|
LPRECT lprc)
|
|
{
|
|
PWND pwnd;
|
|
|
|
if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Must do special validation here to make sure pwnd is a dialog window.
|
|
*/
|
|
if (!ValidateDialogPwnd(pwnd))
|
|
return FALSE;
|
|
|
|
lprc->left = XPixFromXDU(lprc->left, PDLG(pwnd)->cxChar);
|
|
lprc->right = XPixFromXDU(lprc->right, PDLG(pwnd)->cxChar);
|
|
lprc->top = YPixFromYDU(lprc->top, PDLG(pwnd)->cyChar);
|
|
lprc->bottom = YPixFromYDU(lprc->bottom, PDLG(pwnd)->cyChar);
|
|
|
|
return TRUE;
|
|
}
|
|
|