Q257812: BUG: MFC Dialog Explicitly Owned by the Desktop Disables Desktop
Article: Q257812
Product(s): Microsoft C Compiler
Version(s): winnt:5.0,6.0
Operating System(s):
Keyword(s): kbDlg kbMFC kbVC500bug kbVC600bug kbDSupport kbGrpDSMFCATL
Last Modified: 07-MAY-2001
-------------------------------------------------------------------------------
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 <AfxPriv.h> //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 1986-2002.