C++/CLI: Catching all (.NET/Win32/CRT) exceptions
I know this is frowned upon, but I'm out of options here. I'm developing a C++/CLI app that has a bug that I'm unable to track down - mainly because it's bypassing my current crash handler:
AppDomain::CurrentDomain->UnhandledException += gcnew UnhandledExceptionEventHandler(&LogAndExit);
Application::ThreadException += gcnew ThreadExceptionEventHandler(&LogAndExit);
Application::SetUnhandledExceptionMode(UnhandledExceptionMode::CatchException);
try
{
Application::Run(gcnew frmMain());
}
catch (Exception^ ex)
{
LogAndExit(ex);
}
catch (...)
{
LogAndExit();
}
Standard .NET crash handling, I suppose. MSDN reports tha开发者_开发技巧t some of the CRT exceptions will blow over the managed stack and silently abort the app.
I've been reading up on _set_invalid_parameter_handler, but even though I'm getting a LNK2001 error, it seems it can't be used with /clr:pure. Am I right, or am I just PEBKACing it up and missing a lib file?
Can you run in /clr
mode? If you can then try this:
#include <exception>
Then:
try
{
try
{
Application::Run(gcnew frmMain());
}
catch(const exception& ex)
{
throw gcnew System::Exception(gcnew System::String(ex.what()));
}
}
catch (Exception^ ex)
{
LogAndExit(ex);
}
catch (...)
{
LogAndExit();
}
Another thing to note: if your application is multi-threaded, then you will only catch an exception from the thread in which frmMain()
is running. So doing a catch-all on your entire application is impossible in that case!
First of all, this doesn't work for forms.
In applications that use Windows Forms, unhandled exceptions in the main application thread cause the Application.ThreadException event to be raised. If this event is handled, the default behavior is that the unhandled exception does not terminate the application, although the application is left in an unknown state. In that case, the UnhandledException event is not raised. This behavior can be changed by using the application configuration file, or by using the Application.SetUnhandledExceptionMode method to change the mode to UnhandledExceptionMode.ThrowException before the ThreadException event handler is hooked up. This applies only to the main application thread. The UnhandledException event is raised for unhandled exceptions thrown in other threads.
Second, there might be an unmanaged exception (which is not of type System::Exception).
try { Application::Run(gcnew frmMain()); }
catch (Exception^ ex) { LogAndExit(ex); }
catch (...) { LogAndExit(new Exception("Some Unmanage exception"));
msdn- How to catch exceptions in Visual C++
I recommend you try a __try / __except
__try
{
Application::Run(gcnew frmMain());
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LogAndExit(new Exception("Some Unmanage exception"));
}
MSDN documentation here:
http://msdn.microsoft.com/en-us/library/s58ftw19(v=vs.80).aspx
If you wanted to get really tricky, you could try double wrapping it like this:
__try
{
try {
Application::Run(gcnew frmMain());
}
catch(SEHException^ e)
{
LogAndExit(new Exception("Some Unmanage exception"));
}
catch(...) //Leave this out if you're /clr:pure
{
LogAndExit(new Exception("Some Unmanage exception"));
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LogAndExit(new Exception("Some Unmanage exception"));
}
Structured exceptions are wrapped into SEHException^ generally.
You also need to take into account that you may in fact be catching the exception, but that something in your LogAndExit method is causing a secondary exception to be thrown which is actually what is ending your program. Try stubbing out your LogAndExit function and see if you can make the crash happen silently rather than with a standard abort message and/or wrap your LogAndExit code in another try/catch that hides any exceptions.
As someone who has put significant time into C++/CLI, I can sympathize with your dilemma. Hope this solution helps.
Additional MSDN documentation on C++/CLI exception handling:
How to: Define and Install a Global Exception Handler http://msdn.microsoft.com/en-us/library/171ezxzc.aspx
Exception Handling under /clr http://msdn.microsoft.com/en-us/library/633chdda.aspx
There are several types of exception handling. What you posted will only handle managed exceptions.
It's also possible for C++ code to throw unmanaged exceptions (particularly from the standard library). Furthermore, it's possible for unmanaged code to throw a Win32 exception.
Start here and read up on structured exception handling (Win32 exceptions). C++ exceptions and managed exceptions are built on SEH, so if you handle SEH at the top point of every thread in your process, you'll be covered.
Not every crash is an exception, at least not immediately. It's entirely possible for a wild pointer to stomp on .NET internal data structures so badly that when an exception is thrown, the managed handler can't run correctly.
Try using a native handler instead. Visual C++ provides __try
/__except
, but you'll need to make sure the handler is on the call stack of every thread in your program, and it's still possible for an exception to go unhandled (e.g. CreateThread with a pointer to an illegal instruction). To deal with all edge cases, you should instead use SetUnhandledExceptionFilter
.
Note that with /clr:pure
, all code is dependent on the CLR, and so subject to failure due to runtime corruption. Even native handlers might depend on corrupted state, although they're less fragile that MSIL-based handlers. For robust error-handling, you really need code running outside the process.
精彩评论