QA: How to implement "graceful shutdown" in application with modal dialog boxes?

Alexander Shargin (rudankort@softspb.com), May 22, 2002.

Question

My application uses a number of modal dialog boxes to interact with the user. But I've noticed that when a dialog box is opened I can't shutdown the application "gracefully" using Settings->System->Memory window. How can I fix this?

Answer

First let me explain why application can't be stopped when a modal dialog box is active. When you tap Stop button the system finds the application's main window and sends WM_CLOSE message to it. In response to this message the application can terminate cleanly. But if the main window is disabled WM_CLOSE message is not sent and the application can't stop. Modal dialog box disables its owner window "by definition". If modal dialog box is owned by application's main window (which is often the case) the main window is disabled and clean termination is impossible untill the dialog is closed by user.

After I discovered all this I asked myself why the owner window of a modal dialog box must be disabled at all. This measure is supposed to prevent the user from interacting with the owner window while the dialog box is open. But on Pocket PC such an interaction is impossible in any case since owner window is totally obscured by (full-screen) dailog box. So we can leave the main window in enabled state without compromising application usability.

The next question is, how can we skip disabling the main window when a modal dialog box is created. This action is performed deep in DialogBox function (or CWnd::DoModal method in MFC applications) and we can not alter this behaviour. What we can do is reenable the main window after it has been disabled. In MFC-based application this can be done in WN_INITDIALOG handler. In "pure API" application's main window is disabled after WM_INITDIALOG message is sent so we must reenable it later (e. g. in WM_ERASEBKGND handler).

Soureces

The implementation of this idea looks like this.

Win API:

// In dialog proc case WM_ERASEBKGND: { HWND hOwner = GetWindow(hDlg, GW_OWNER); if(IsWindow(hOwner)) { EnableWindow(hOwner, TRUE); // enable main window return FALSE; } }

MFC:

// WM_INITDIALOG message handler BOOL CSomeDlg::OnInitDialog() { CDialog::OnInitDialog(); AfxGetMainWnd()->EnableWindow(); // enable application's main window ... }

If the owner window of a dialog box is not the main window of your application you have no need to use this code (although using it will not harm your program as well).