Add wxApp::StoreCurrentException() and RethrowStoredException().

These methods can be used to ensure that the exceptions thrown from event
handlers are safely rethrown from the code dispatching the events once the
control flow gets back there.

This allows to work around the problem with not being able to propagate
exceptions through non-C++ code and can be used, for example, to catch
exceptions thrown by the handlers invoked from inside wxYield() by a try/catch
block around wxYield() -- something that didn't work before, update the except
sample to show that it does work now.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@77468 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2014-08-24 15:31:44 +00:00
parent c779385a1a
commit 1cecee5bb7
9 changed files with 333 additions and 22 deletions

View File

@@ -1624,24 +1624,59 @@ bool wxEvtHandler::SafelyProcessEvent(wxEvent& event)
loop->Exit();
}
//else: continue running current event loop
return false;
}
catch ( ... )
{
// OnExceptionInMainLoop() threw, possibly rethrowing the same
// exception again: very good, but we still need Exit() to
// be called, unless we're not called from the loop directly but
// from Yield(), in which case we shouldn't exit the loop but just
// unwind to the point where Yield() is called where the exception
// might be handled -- and if not, then it will unwind further and
// exit the loop when it is caught.
// exception again. We have to deal with it here because we can't
// allow the exception to escape from the handling code, this will
// result in a crash at best (e.g. when using wxGTK as C++
// exceptions can't propagate through the C GTK+ code and corrupt
// the stack) and in something even more weird at worst (like
// exceptions completely disappearing into the void under some
// 64 bit versions of Windows).
if ( loop && !loop->IsYielding() )
loop->Exit();
throw;
// Give the application one last possibility to store the exception
// for rethrowing it later, when we get back to our code.
bool stored = false;
try
{
if ( wxTheApp )
stored = wxTheApp->StoreCurrentException();
}
catch ( ... )
{
// StoreCurrentException() really shouldn't throw, but if it
// did, take it as an indication that it didn't store it.
}
// If it didn't take it, just abort, at least like this we behave
// consistently everywhere.
if ( !stored )
{
try
{
if ( wxTheApp )
wxTheApp->OnUnhandledException();
}
catch ( ... )
{
// And OnUnhandledException() absolutely shouldn't throw,
// but we still must account for the possibility that it
// did. At least show some information about the exception
// in this case.
wxTheApp->wxAppConsoleBase::OnUnhandledException();
}
wxAbort();
}
}
}
#endif // wxUSE_EXCEPTIONS
return false;
}
bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)