How do I handle situations when the my app is terminating, using a callback prior to termination?
The .NET handlers do not work in the following scenario, is SetUnhandledExceptionHandler the correct choice? It appears to have the shortcomings discussed in the following.
Scenario
I want to respond to all cases of app termination with a message and error report to our service in our .net app.
However, I have a WPF app in which two of our testers get unhandled exceptions that bypass:
- AppDomain.UnhandledException (most importantly)
- Application.ThreadException
- Dispatcher.UnhandledException
They are marked SecuirtyCritical and HandleProcessCorruptedStateExceptions. legacyCorruptedStateExceptionsPolicy is set to true in the app.config
My two examples in the wild
- VirtualBox running widows10 throws inside some vboxd3d.dll when initialising WPF somewhere (turning off vbox 3d accel "fixes it")
- Win8 machine with suspicious option to "run on graphics card A/B" in system context menu, crashes somewhere (:/) during WPF startup but only when anti-cracking tools are applied.
Either way, when live, the app must to respond to these kinds of failures prior to termination.
I can reproduce this with an unmanaged exception, that occurs in an unmanaged thread of a PInvoked method in .net:
test.dll
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DWORD WINAPI myThread(LPVOID lpParameter)
{
long testfail = *(long*)(-9022);
return 1;
}
extern "C" __declspec(dllexport) void test()
{
DWORD tid;
HANDLE myHandle = CreateThread(0, 0, myThread, NULL, 0, &tid);
WaitForSingleObject(myHandle, INFINITE);
}
app.exe
class TestApp
{
[DllImport("kernel32.dll")]
static extern FilterDelegate SetUnhandledExceptionFilter(FilterDelegate lpTopLevelExceptionFilter);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate int FilterDelegate(IntPtr exception_pointers);
static int Win32Handler(IntPtr nope)
{
MessageBox.Show("Native uncaught SEH exception"); // show + report or whatever
Environment.Exit(-1); // exit and avoid WER etc
return 1; // thats EXCEPTION_EXECUTE_HANDLER, although this wont be called due to the previous line
}
[DllImport("test.dll")]
static extern void test();
[STAThread]
public static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
SetUnhandledExceptionFilter(Win32Handler);
test(); // This is caught by Win32Handler, not CurrentDomain_UnhandledException
}
[SecurityCritical, HandleProcessCorruptedStateExceptions ]
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
MessageBox.Show(ex.ToString()); // show + report or whatever
Environment.Exit(-1); // exit and avoid WER etc
}
}
This handles the failure in the vboxd3d.dll in a bare WPF test app, which of course also has the WCF Dispatcher and WinForms Application (why not) exception handlers registered.
Updates
- In the production code I am trying to use this on, the handler appears to get overwritten by some other caller, I can get around that by calling the method every 100ms which is stupid of course.
- On the machine with the vbox3d.dll problem, doing the above replaces the exception with one in clr.dll.
- It appears at the time of crash, the managed function pointer passed into kernel32 is no longer valid. Setting the handler with a native helper dll, which calls a native function inside appears to be working. The managed function is a static method - I'm not sure pinning applies here, perhaps the clr is in the process of terminating...
- Indeed the managed delegate was being collected. No "overwriting" of the handler was occuring. I've added as an answer..not sure what to accept or what the SO convention is here...