0

If I test an MFC app by sending it an WM_ENDSESSION and TRUE that is ending, the framework of MFC calls OnCloseDocument(). All good! But I find that when Windows update or the MSI Installer wants to reboot after installing something it, the 'OnCloseDocument()' is not called and all data is lost.

Looking at the MFC code you see:

// when Windows session ends, close all documents
void CFrameWnd::OnEndSession(BOOL bEnding)
{
    if (!bEnding)
        return;

    CWinApp* pApp = AfxGetApp();
    if (pApp != NULL && pApp->m_pMainWnd == this)
    {
        if (AfxGetThreadState()->m_lastSentMsg.lParam & ENDSESSION_CLOSEAPP)
        {
            // Restart Manager is restarting the application
            CDataRecoveryHandler *pHandler = pApp->GetDataRecoveryHandler();
            if (pHandler)
            {
                pHandler->SetShutdownByRestartManager(TRUE);

                // Just return here rather than doing more processing.
                // The final autosave will be handled in the WM_CLOSE handler,
                // because the Restart Manager allows 30 seconds for processing
                // that message, and only 5 seconds for processing WM_ENDSESSION.
                return;
            }
        }

        AfxOleSetUserCtrl(TRUE);    // keeps from randomly shutting down
        pApp->CloseAllDocuments(TRUE);

        // allow application to save settings, etc.
        pApp->ExitInstance();
    }
}

I presume what must be happening is the ENDSESSION_CLOSEAPP section is being called, which doesn't end up saving anything.

This is the code in the app constructor for the restart manager:

  // support Restart Manager
  m_dwRestartManagerSupportFlags=AFX_RESTART_MANAGER_SUPPORT_RESTART | AFX_RESTART_MANAGER_SUPPORT_RECOVERY;

Since I don't need autosave, but even if autosave is 5 minutes it still may not have changes saved. What is the correct way to handle it in MFC to ensure the OnCloseDocument() is called when WM_ENDSESSION is sent?

user3161924
  • 1,849
  • 18
  • 33
  • MFC does process the `WM_QUERYENDSESSION` message (sent prior to `WM_ENDSESSION`), asking the user to save the modified documents (see `CFrameWnd::OnQueryEndSession()` in winfrm.cpp). For this to work you need to call `pDoc->SetModifiedFlag()` in every action that modifies it. If you already do so (so either message is not sent), then it's a problem of Windows, not of your app, and you can't do anything about it. It's hard to reproduce and test/debug, and imo it's not too serious (rarely occurs and you must have unsaved data during update/restart!) so maybe not worth to fix. But if want... – Constantine Georgiou Jul 15 '22 at 08:00
  • it's one set of data not files that can be opened and closed, but the setup used doc/view mfc, so it saves under the `CloseDocument()`. you don't know if it will actually be closed on the query, only at the `OnEndSession` with the `bEnding` true. – user3161924 Jul 15 '22 at 17:01
  • Don't know the details of your implementation. However the source code you posted does call `pApp->CloseAllDocuments(TRUE);`, unless... the Restart Manager is involved or `bEnding` is `FALSE`. Could you override it in your frame-window class (so you can test/trace it) to check what's going on exactly? You could then remove that part. Or change your app so that it doesn't support the Restart Manager operations, after all does it make any sense for this kind of application? – Constantine Georgiou Jul 15 '22 at 17:59
  • the code is from MFC. I was wondering the correct method to catch all shutdowns. – user3161924 Jul 16 '22 at 01:27
  • To me the "correct" method would be to process the `WM_QUERYENDSESSION` message. But the application's architecture as it is now does not allow it, or requires big (?) changes. This code is from MFC, but you can use it in your app, to find out what's going on: in your `CMainFrame` class, go to the Properties, Messages, and add the handler for the `WM_ENDSESSION` (OnEndSession()) and copy the code in there - do not call CFrameWnd()::OnEndSession(); you may need to add some #include directives (headers) for the code to compile. Then you can trace/debug it. – Constantine Georgiou Jul 16 '22 at 14:48

0 Answers0