To prevent the exception handler from being called recursively, or to prevent the exception handler from being called again if it throws an exception, you can use a spin-wait exception handler.
__declspec(noinline) void SpinForever(){ while (true) { SwitchToThread(); }}
DWORD s_ExceptionThreadID = 0;
LONG WINAPI SpinWaitExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo){ if (s_ExceptionThreadID == GetCurrentThreadId()) { // Prevent recursive exception locking the dump process std::cout << "EXCEPTION HANDLER: Recursive exception encountered, skipping inner exception" << std::endl; } else { SpinForever(); }
return 0;}
LONG WINAPI BasicUnhandledExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo){ s_ExceptionThreadID = GetCurrentThreadId(); SetUnhandledExceptionFilter(SpinWaitExceptionHandler);
...
return EXCEPTION_CONTINUE_SEARCH;}
When putting this into practice, you may want to write a minidump file when an unhandled exception occurs. This can be done using the MiniDumpWriteDump function.
#include <DbgHelp.h>
BOOL WriteDump(const TCHAR* Path, EXCEPTION_POINTERS* ExceptionInfo, bool bIsFullMemory, DWORD ExceptionThreadId){ HANDLE FileHandle = CreateFileW(Path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (FileHandle == INVALID_HANDLE_VALUE) { return false; }
MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo; DumpExceptionInfo.ThreadId = ExceptionThreadId; DumpExceptionInfo.ExceptionPointers = ExceptionInfo; DumpExceptionInfo.ClientPointers = FALSE;
MINIDUMP_TYPE mdt = MiniDumpNormal; if (bIsFullMemory) { mdt = MiniDumpWithFullMemory; }
const BOOL Result = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), FileHandle, mdt, (ExceptionInfo ? &DumpExceptionInfo : NULL), NULL, NULL); CloseHandle(FileHandle);
return Result;}
Demonstrating of how these functions can be used together, along with reporting the exception through the Windows Error Reporting API can be found in WERCrashApp.