I have error handling code that is designed to catch unnhandled exceptions, and then create a dump.
Now, i've encountered a few situations where this doesn't work well in the transition between Native and managed code.
For example if in a Paint()
event I call some native code, and that native code throws an exception.
The message loop dispatcher will catch the native exception, and then rethrow a .NET SEHException
.
Same thing happens sometimes with DLLS that host COM objects.
The problem with this is that because of the stack-roll back and the way it catches and creates an SEHException
from the native exception, the actual Native call stack is destroyed.
Can i get the native call stack somehow, using the SEHException
? (note that the call stack in the SEHException is the CLR call stack).
Or can i set the application so it will save the call stack somehow ?
What happens is that .Net called Paint()
when it needed to paint a window.
Apparently .Net made this very safe and added extra precautions and error handling.
Now my Paint()
event called a C++/CLI wrapper dll that called a native C++ dll. The native C++ exception raised an Access Violation exception.
Now the .Net caught that exception, and wrapped it up as a managed SEHException
object, and I've lost all the call stack from the actual error point.
Solution:
We need to catch the exception before the .Net exception handling.
The usual exception handling flow can be found on the net, but this sites gives a good example of the actual flow: Exception handlers
It seems that the .Net catches the exceptions and wraps them before the SetUnhandledExceptionFilter handler is called.
So, I've added a first chance exception handler with AddVectoredExceptionHandler
and checked for fatal exceptions by checking the errorcode.
//SEH exceptions have code 0xC0000xxxx
#define SEH_TYPE (DWORD)0xC0000000L
//mask the last byte
#define SEH_MASK (DWORD)0xFF000000L
LONG WINAPI CheckForSEHException( struct _EXCEPTION_POINTERS *lpTopLevelExceptionFilter)
{
if ((lpTopLevelExceptionFilter->ExceptionRecord->ExceptionCode & SEH_MASK) == SEH_TYPE) //mask and check the last bits if it's an SEH exception
{
//handle exception here (create a dump or something)
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
The exception codes can be found in WinBase.h, you can follow the definitions to the actual error codes. (ie. look for EXCEPTION_ACCESS_VIOLATION
)