You are currently offline, waiting for your internet to reconnect

PRB: Modal Dialog Box Prevents Calls to PreTranslateMessage

This article was previously published under Q126874
This article has been archived. It is offered "as is" and will no longer be updated.
NOTE: This article contains references to CWinApp member functions. In the32-bit version of MFC, the bulk of the code for these functions is actuallyimplemented in the CWinThread class from which CWinApp is derived.
PreTranslateMessage is not called when a modal dialog box has been invoked.A modal dialog box has its own message loop, which has no interaction withthe application's main message loop. This prevents CWinApp::PumpMessagefrom being called. PumpMessage is the function that callsPreTranslateMessage.
An application is begun by a call to WinMain. MFC's implementation ofWinMain calls CWinApp::Run, which has the application's main message loop.

The message loop in Run calls PumpMessage to process messages. PumpMessageretrieves the messages from the application's message queue using theGetMessage API. PumpMessage then calls CWinApp::PreTranslateMessage, whichwill call PreTranslateMessage for the appropriate CWnd. For details onMFC's message routing mechanism, see MFC TechNote #21 and examine theCWinApp::PreTranslateMessage function in the MFC source code that can befound in APPCORE.CPP. In the 32-bit version of MFC, this code is inCWinThread::PreTranslateMessage and can be found in THRDCORE.CPP. Here is apicture of this process:
                  -------------------------------------                 |         CWinApp::PumpMessage        |                  -------------------------------------                                     |                                     |                  -------------------------------------                 |     CWinApp::PreTranslateMessage    |                  -------------------------------------                                     |                                     |                  -------------------------------------                 |       CWnd:: PreTranslateMessage    |                  -------------------------------------				
When a modal dialog box has been invoked, the above sequence is no longerused. A modal dialog box uses the Dialog Manager (the code built intoWindows for implementing dialog boxes) to retrieve messages from theapplication's message queue and process them. In other words, the DialogManager takes control of all message processing during the existence of amodal dialog box. Here's a picture of this process:
                  -------------------------------------                 |          CWinApp::PumpMessage       |                  -------------------------------------                                    |                                    |                  -------------------------------------                 |           CDialog::DoModal          |                  -------------------------------------                                    |                                    |                  -------------------------------------                 |     Dialog Manager's Message Loop   |                  -------------------------------------				
The PumpMessage has dispatched the message that invoked the dialog box inthe first place. PumpMessage will not be called again until the DialogManager exits its message loop -- when the modal dialog box has beendismissed.

However, a modeless dialog box uses the normal message processing sequencebecause it uses the application's message loop, not the Dialog Manager'smessage loop.
PreTranslateMessage is generally overidden to check for certain messagesand do some specialized or additional processing before these messages aretranslated and dispatched. Because PreTranslateMessage will not be calledwhile a modal dialog box exists, another technique must be used to achievethis processing.

The additional message processing can be achieved by using one of thefollowing two methods:

  1. Use a modeless dialog box to simulate a modal dialog box. To do this, create a modeless dialog box, and then disable the application's main frame window. This method causes the normal message processing sequence to be followed, so the PreTranslateMessage function is called. The application's main window can be disabled by using this:
    This window should be re-enabled once the dialog box has been destroyed. Use the following call to do it:
    One possible place to do this might be in the CDialog-derived object's PostNcDestroy function that gets called when the dialog box window itself (the HWND) is destroyed.

    If you have multiple top-level windows in your application you may also want to disable the other windows. This can be done for the other windows in the same way -- by using EnableWindow.
  2. If a modal dialog box seems necessary, perform the additional message processing by overiding the CWinApp::ProcessMessageFilter function. The ProcessMessageFilter function gets called for all messages when a modal dialog box exists. This is set up for you by MFC using a WH_MSGFILTER hook. See the ProcessMessageFilter documentation for details. The following sample code illustrates this concept:
       BOOL CMyApp::ProcessMessageFilter(int code, LPMSG lpMsg)   {     // Check to see if the modal dialog box is up     if (m_hwndDialog != NULL)       if (lpMsg->hwnd == m_hwndDialog ||           ::IsChild(m_hwndDialog, lpMsg->hwnd))         {           // Use the global IsChild() function to get           // messages destined for the dialog's controls           // Perform customized message processing here         }     return CWinApp::ProcessMessageFilter(code, lpMsg);   }						
In the above sample code m_hwndDialog is a member variable of the CWinAppderived class that holds the handle of the modal dialog box. This variableshould be initialized to m_hWnd of the modal dialog in the OnInitDialogfunction, and should be set to NULL when the modal dialog is destroyed.Also the variable should be initialized in the CWinApp-derived object'sconstructor. For example:
// The OnInitDialog to initialize m_hwndDialog// CMyDialog::OnInitDialog(){  CDialog::OnInitDialog();  ((CMyApp *)AfxGetApp())->m_hwndDialog=m_hWnd;}// When the dialog is destroyed restore m_hwnDialog to NULL// void CMyDialog::PostNcDestroy(){  CDialog::PostNcDestroy();  ((CMyApp *)AfxGetApp())->m_hwndDialog=NULL;}// The CWinApp object's constructor to initialize m_hwndDialogCMyApp::CMyApp(){  m_hwndDialog=NULL;}				
This behavior is by design.
Books Online: MFC TechNote #21.

"Meandering Through the Maze of MFC Message and Command Routing" byPaul DiLascia in the July 1995 issue of "Microsoft Systems Journal"(Volume 10, Number 7).
1.00 1.50 2.00 2.10 2.50 2.51 3.00 3.10 4.00 WM_KEYDOWN

Article ID: 126874 - Last Review: 12/04/2015 11:07:35 - Revision: 1.1

Microsoft Foundation Class Library 4.2

  • kbnosurvey kbarchive kbcode kbprb kbuidesign KB126874