Microsoft KB Archive/257812

= BUG: MFC Dialog Explicitly Owned by the Desktop Window Disables the Desktop =

Article ID: 257812

Article Last Modified on 12/11/2003

-

APPLIES TO


 * Microsoft Visual C++ 5.0 Enterprise Edition
 * Microsoft Visual C++ 6.0 Enterprise Edition
 * Microsoft Visual C++ 5.0 Professional Edition
 * Microsoft Visual C++ 6.0 Professional Edition
 * Microsoft Visual C++ 6.0 Standard Edition

-



This article was previously published under Q257812



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.



Steps to Reproduce Behavior
 Create a dialog-based application, Prj1, and accept all the defaults.  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));  Build and run the application. Click the mouse anywhere, and notice you do not get any response. Press ALT+TAB until you bring the focus back to the dialog application and then press Enter or Escape.</li></ol>

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: kbbug kbdlg kbpending KB257812

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.