From 01fac4b748c5127601f91c098adcabc5efb93073 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 15 Aug 2017 00:41:16 +0200 Subject: [PATCH] Delete windows before application on session end in wxMSW When WM_ENDSESSION was received by the application, the wxApp object itself was shut down by calling OnExit() on it before all the TLWs were destroyed, which could be completely unexpected as during normal shutdown the order of events is exactly the reverse. In practice, this resulted in crashes in any application whose main window close event handler or dtor touched wxTheApp in any way (e.g. to save any configuration in the global wxConfig object destroyed by wxApp::OnExit()). See #9590 (sorry for missing the point before, ATS). --- include/wx/app.h | 4 ++++ src/common/appcmn.cpp | 22 ++++++++++++++-------- src/msw/app.cpp | 7 +++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/wx/app.h b/include/wx/app.h index 0201c8c7b2..d16f209732 100644 --- a/include/wx/app.h +++ b/include/wx/app.h @@ -684,6 +684,10 @@ protected: // override base class method to use GUI traits virtual wxAppTraits *CreateTraits() wxOVERRIDE; + // Helper method deleting all existing top level windows: this is used + // during the application shutdown. + void DeleteAllTLWs(); + // the main top level window (may be NULL) wxWindow *m_topWindow; diff --git a/src/common/appcmn.cpp b/src/common/appcmn.cpp index fc784f6e7c..bc48e9fc4d 100644 --- a/src/common/appcmn.cpp +++ b/src/common/appcmn.cpp @@ -127,6 +127,18 @@ wxAppBase::~wxAppBase() // this destructor is required for Darwin } +void wxAppBase::DeleteAllTLWs() +{ + // TLWs remove themselves from wxTopLevelWindows when destroyed, so iterate + // until none are left. + while ( !wxTopLevelWindows.empty() ) + { + // do not use Destroy() here as it only puts the TLW in pending list + // but we want to delete them now + delete wxTopLevelWindows.GetFirst()->GetData(); + } +} + void wxAppBase::CleanUp() { // Clean up any still pending objects. Normally there shouldn't any as we @@ -135,14 +147,8 @@ void wxAppBase::CleanUp() // the base class OnExit(). DeletePendingObjects(); - // and any remaining TLWs (they remove themselves from wxTopLevelWindows - // when destroyed, so iterate until none are left) - while ( !wxTopLevelWindows.empty() ) - { - // do not use Destroy() here as it only puts the TLW in pending list - // but we want to delete them now - delete wxTopLevelWindows.GetFirst()->GetData(); - } + // and any remaining TLWs + DeleteAllTLWs(); // undo everything we did in Initialize() above wxBitmap::CleanUpHandlers(); diff --git a/src/msw/app.cpp b/src/msw/app.cpp index d205f7e6ef..27a4ca23e7 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -839,6 +839,13 @@ void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event)) if ( !wxTopLevelWindows.empty() ) wxTopLevelWindows[0]->SetHWND(0); + // Destroy all the remaining TLWs before calling OnExit() to have the same + // sequence of events in this case as in case of the normal shutdown, + // otherwise we could have many problems due to wxApp being already + // destroyed when window cleanup code (in close event handlers or dtor) is + // executed. + DeleteAllTLWs(); + const int rc = OnExit(); wxEntryCleanup();