Created
May 22, 2011 15:44
-
-
Save thinkhy/985598 to your computer and use it in GitHub Desktop.
The source code of DialogBox windows implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***************************************************************************\ | |
* 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); | |
if (FWINABLE()) { | |
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; | |
} | |
} | |
if (FWINABLE()) { | |
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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment