Exception Handling in Windows
Windows provides the following exception handling frameworks:
- Structured Exception Handling (SEH)
- Vectored Exception Handling (VEH)
SEH is just the Windows's version of the C++ try-catch
, and documentation suggests using the C++ try-catch
blocks. I don't want to use try-catch
everywhere but have a single 'catch-all' exception handler.
That leads to VEH, which, unlike SEH is not a frame-based exception handling construct (frame-based exception handling is defined here). VEH is for the entire process and not just each thread. This post describes VEH contrasted with SEH.
But there is one more technique - UnHandledExceptionFilter. This is actually part of SEH. In Windows, the __except
part contains a filter expression (described in detail here), which decides whether to invoke the exception handler (which follows the __except
clause or pass it to other exception handlers in the stack).
__try {
// guarded code
}
__except ( /* filter expression */ ) {
// the exception handler (as Windows calls it)
}
Now, if none of the exception handlers are matched, then the exception handler set using the SetUnhandledExceptionFilter
method is invoked. To me, it looks like a non-frame-based exception handler (like VEH), but this is also the last handler which catches all exceptions that weren't caught by the SEH's __except
clause, which is frame-based. In my case, if I don't write any try-except
blocks, the method I set using SetUnhandledExceptionFilter
gets invoked - which makes sense because there were 0 exception handlers, so by default, all exceptions are considered 'unfiltered' and trigger the UnhandledExceptionFilter.
Now, I'm not sure which one to use - VEH or UnhandledExceptionFilter
. VEH is not frame-based and gets invoked before all frame-based exception handlers (SEH) and UnhandledExceptionFilter
. Both can handle all 'uncaught exceptions'.
Next, after catching an exception (using VEH or UnhandledExceptionFilter
) on a worker thread (threads created by app), what is the expectation? Can the app continue?
Here's a sample scenario: If there was a division by zero or access violation due to a bug on a worker thread, I'd like to signal the main thread and kill the worker thread. The main thread finalizes all my structures, shows a message box to user with two options - Restart & Quit, and if user chooses to Restart, initialize all my structures again. This is possible but is this recommended?
Regarding return values, VEH documentation says:
To return control to the point at which the exception occurred, return EXCEPTION_CONTINUE_EXECUTION (0xffffffff). To continue the handler search, return EXCEPTION_CONTINUE_SEARCH (0x0).
and UnhandledExceptionFilter documentation says there are the following return values - EXCEPTION_CONTINUE_SEARCH and EXCEPTION_EXECUTE_HANDLER, different from VEH.
What if an exception occurs in the main thread? Then, the VEH and UnhandledExceptionFilter
gets invoked on main thread. I can't kill the thread in that scenario. What is Window's recommendation?
There's also this other stackoverflow post which says VEH doesn't replace UnhandledExceptionFilter
and should be used as a diagnostic tool only, but I didn't understand.
Basically, I want to know Windows's recommended way to cleanly handle exceptions in a Windows app. Summarizing my questions as follows:
- VEH vs
UnhandledExceptionFilter
- which one to use and why? What is Windows's recommendation? - After catching an exception (in both cases - main thread or worker thread), how should the app behave?
Note: I'm aware that killing a thread is not a good practice and has some consequences (one being, the stack doesn't unwind), but that's not the main focus of this post. If I kill the thread, I don't have to deal with recursive exceptions and I can potentially restart the app in the same process space.
Update1: I cannot use try-catch
for few reasons - it works only if you throw an exception (I might be wrong here)... It doesn't catch division by zero (as shown here). I'm not hands-on with it, but it's a guideline in my project to never use try-catch
, unless a third-party API which throws, is used. All funcs are marked noexcept
. There are other reasons, but that'd digress from this post.