Q
When I use a modeless dialog in the SDK, I have to insert a statement in
the main loop like this:
while(GetMessage(&msg,NULL,0,0) {
if(!IsDialogMessage(hdlg,&msg){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
My question is: why do I need this IsDialogMessage call? Isn't a
modeless dialog just another window like the main window? So without
this addition can't the message be dispatched to the dialog? If I have
to add this statement, does that mean that if I have several modeless
dialogs I have to add a separate IsDialogMessage call for each one? If
so, how does MFC handle this? I can't touch the main loop in MFC, so how
do I add IsDialogMessage to it?
Hua YuanA
Yikes—that's more than one question! But let me try to answer. First of
all, part of the confusion is the name. The purpose of IsDialogMessage
isn't to check whether the message is for the dialog; it's to translate
the message. A better name would be TranslateDialogMessage.
As with TranslateAccelerator in the previous question, IsDialogMessage
translates messages for modeless dialogs. For example, it maps
Tab and Shift+Tab to the next/previous control, and maps the arrow
keys to their respective operations in a dialog. You can think of it as
translating the message based on a special built-in accelerator table just
for dialogs. In fact, you don't have to use IsDialogMessage for dialogs—you
can use it for any window that contains controls to get the same keyboard
behavior as a dialog. But, since the first argument of IsDialogMessage is the
HWND of the dialog, you do in fact have to call it for every modeless dialog
your app has running at a given time. Normally you'd have a global HWND
variable, g_hDlg, that you set when you create the dialog.
That explains why you need IsDialogMessage, and answers the question,
"Do I have to add one call for each dialog?" The next question is: how does
MFC handle this? As I described for the previous question, MFC uses a
sophisticated routing scheme using the virtual function CWnd::PreTranslateMessage,
which lets any window hook itself into the main loop without modifying the
loop itself. The default implementation for CDialog::PreTranslateMessage
looks like this:
BOOL CDialog::PreTranslateMessage(MSG* pMsg)
{
•••
// many lines of intimidating code
•••
return PreTranslateInput(pMsg);
}
In other words, CDialog passes the buck to yet another virtual function,
CWnd::PreTranslateInput:
BOOL CWnd::PreTranslateInput(LPMSG lpMsg)
{
if (/* keyboard or mouse message */)
{
return IsDialogMessage(lpMsg);
}
return FALSE;
}
As you might guess, CWnd::IsDialogMessage is a wrapper that calls
::IsDialogMessage with m_hWnd as the HWND. The result of all this is that
in MFC, each dialog translates its own input. If you have five dialogs
running, each dialog's PreTranslateMessage calls IsDialogMessage—so you don't
have to. Pretty nifty! In MFC, you don't ever have to worry about
IsDialogMessage—it gets taken care of automatically.
---
|