1
votes

I have an MFC dialog based application where I want to change the dialog. To do this I close the dialog and try to load it again with another dialog template. The second invocation of the dialog fails with a return code of -1.

Even without changing the template, the problem stays the same. GetLastError() returns 0. I have used AppWizard to generate the simplest possible example.

The App wizard generates the following code in CMyApp::InitInstance:

CMyAppDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
    ...

This I changed to:

CMyAppDlg *pdlg = new CMyAppDlg;
m_pMainWnd = pdlg;
INT_PTR nResponse = pdlg->DoModal();
if (nResponse == IDOK)
{}
delete pdlg;

CMyAppDlg dlg1;
m_pMainWnd = &dlg1; // leaving this out makes no difference
nResponse = dlg1.DoModal();// this exits immediately with a -1
if (nResponse == IDOK)

...

The first DoModal() works fine. When I press OK or Cancel, the second DoModal() fails returning -1.

1
"The second invocation of the dialog fails with a return code of -1." Did you try seeing what GetLastError returns, after you see such return value, as described in the documentation?Algirdas Preidžius
@alg: You cannot call GetLastError in an MFC application. Please read the documentation again.IInspectable
@IInspectable Please provide a quote, stating, that one cannot call GetLastError in an MFC application.Algirdas Preidžius
Documentation for CDialog::DoModal says GetLastError gives additional information if DoModal returns IDABORT. Otherwise GetLastError is not useful. In this case GetLastError is 0, because there was no Windows error, it's an MFC issue.Barmak Shemirani
@bar: The documentation doesn't say that.IInspectable

1 Answers

4
votes

From documentation for m_pMainWnd

The Microsoft Foundation Class Library will automatically terminate your thread when the window referred to by m_pMainWnd is closed. If this thread is the primary thread for an application, the application will also be terminated. If this data member is NULL, the main window for the application's CWinApp object will be used to determine when to terminate the thread. m_pMainWnd is a public variable of type CWnd*.

So by the time the main window is close, MFC has already decided that the application is over, additional windows will not be created.

Minimum reproducible code:

BOOL CMyWinApp::InitInstance()
{
    CWinApp::InitInstance();

    CDialog *pdlg = new CDialog(IDD_DIALOG1);
    m_pMainWnd = pdlg; //<- remove this to see the message box
    pdlg->DoModal();
    m_pMainWnd = NULL; //<- this line has no effect basically
    delete pdlg;

    MessageBox(0, L"You won't see this message box", 0, 0);
    TRACE("but you will see this debug line\n");

    return FALSE;
}

To fix it, you can remove the line //m_pMainWnd = pdlg; and let MFC handle it.

Better yet, change the program design so that there is always one main window for the GUI thread.