DOCUMENT:Q257812 07-MAY-2001 [visualc] TITLE :BUG: MFC Dialog Explicitly Owned by the Desktop Disables Desktop PRODUCT :Microsoft C Compiler PROD/VER:winnt:5.0,6.0 OPER/SYS: KEYWORDS:kbDlg kbMFC kbVC500bug kbVC600bug kbDSupport kbGrpDSMFCATL ====================================================================== ------------------------------------------------------------------------------- The information in this article applies to: - Microsoft Visual C++, 32-bit Enterprise Edition, versions 5.0, 6.0 - Microsoft Visual C++, 32-bit Professional Edition, versions 5.0, 6.0 - Microsoft Visual C++, 32-bit Learning Edition, version 6.0 ------------------------------------------------------------------------------- SYMPTOMS ======== When you attempt to explicitly specify the desktop as the owner window for a modal MFC dialog, this action results in a system that does not respond to mouse events. If you click on different controls in the dialog box or on other windows on the desktop, there is no effect. To exit, you must dismiss the dialog box through the keyboard command. CAUSE ===== The MFC code for the CDialog::DoModal function simulates modal dialogs by disabling the owner window of the dialog box. Under normal circumstances, this window is either an application window or sometimes NULL. The MFC code for CDialog::DoModal fails to test whether the dialog's owner is the desktop before MFC disables it. RESOLUTION ========== The easiest workaround is to not explicitly specifying the desktop as the owner of a modal dialog. Instead, accept the default NULL argument which works fine as a default in most cases. However, if you want the desktop to own your dialog then you can override CDialog::DoModal in your dialog class implementation. Note that this is a somewhat difficult task. STATUS ====== Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article. MORE INFORMATION ================ Steps to Reproduce Behavior --------------------------- 1. Create a dialog-based application, Prj1, and accept all the defaults. 2. Go to the CPrj1App::InitInstance function and change the line of code that declares the dialog box variable to read as follows: // Explicitly specify the owner of this dialog to be the desktop. CPrj1Dlg dlg(CWnd::FromHandle(::GetDesktopWindow())); 3. Build and run the application. 4. Click the mouse anywhere, and notice you do not get any response. 5. Press ALT+TAB until you bring the focus back to the dialog application and then press Enter or Escape. Override CDialog::DoModal ------------------------- To work around the problem, provide an override for CDialog::DoModal. Do this by inserting the following code into your application: // XMN: Includes and defines needed to compile DoModal(). // For AfxHookWindowCreate() and AfxUnhookWindowCreate() #include //danger, danger, including private MFC header. // From Mfc\Src\StdAfx.h. #ifndef _AFX_OLD_EXCEPTIONS #define DELETE_EXCEPTION(e) do { e->Delete(); } while (0) #else //!_AFX_OLD_EXCEPTIONS #define DELETE_EXCEPTION(e) #endif //_AFX_OLD_EXCEPTIONS // XMN: Includes and defines needed to compile DoModal(). int CPrj1Dlg::DoModal() { // Can be constructed with a resource template or InitModalIndirect. ASSERT(m_lpszTemplateName != NULL || m_hDialogTemplate != NULL || m_lpDialogTemplate != NULL); // Load resource as necessary. LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate; HGLOBAL hDialogTemplate = m_hDialogTemplate; HINSTANCE hInst = AfxGetResourceHandle(); if (m_lpszTemplateName != NULL) { hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG); HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG); hDialogTemplate = LoadResource(hInst, hResource); } if (hDialogTemplate != NULL) lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate); // Return -1 in case of failure to load the dialog template resource. if (lpDialogTemplate == NULL) return -1; // Disable parent (before creating dialog). HWND hWndParent = PreModal(); AfxUnhookWindowCreate(); BOOL bEnableParent = FALSE; // XMN: Replace next line: // If (hWndParent != NULL && ::IsWindowEnabled(hWndParent)) // XMN: with this line: if (hWndParent != NULL && hWndParent != ::GetDesktopWindow() && ::IsWindowEnabled(hWndParent)) { ::EnableWindow(hWndParent, FALSE); bEnableParent = TRUE; } TRY { // Create modeless dialog. AfxHookWindowCreate(this); if (CreateDlgIndirect(lpDialogTemplate, CWnd::FromHandle(hWndParent), hInst)) { if (m_nFlags & WF_CONTINUEMODAL) { // Enter modal loop. DWORD dwFlags = MLF_SHOWONIDLE; if (GetStyle() & DS_NOIDLEMSG) dwFlags |= MLF_NOIDLEMSG; VERIFY(RunModalLoop(dwFlags) == m_nModalResult); } // Hide the window before enabling the parent, etc. if (m_hWnd != NULL) SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW| SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); } } CATCH_ALL(e) { DELETE_EXCEPTION(e); m_nModalResult = -1; } END_CATCH_ALL if (bEnableParent) ::EnableWindow(hWndParent, TRUE); if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd) ::SetActiveWindow(hWndParent); // Destroy modal window. DestroyWindow(); PostModal(); // Unlock free resources as necessary. if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL) UnlockResource(hDialogTemplate); if (m_lpszTemplateName != NULL) FreeResource(hDialogTemplate); return m_nModalResult; } Additional query words: CDialog DoModal GetDesktopWindow ====================================================================== Keywords : kbDlg kbMFC kbVC500bug kbVC600bug kbDSupport kbGrpDSMFCATL Technology : kbVCsearch kbAudDeveloper kbVC500 kbVC600 kbVC32bitSearch kbVC500Search Version : winnt:5.0,6.0 Issue type : kbbug Solution Type : kbpending ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 2001.