Often an exception filter must analyze the situation before it can determine which value to return. For example, your handler might know what to do if a divide by 0 exception occurs, but it might not know how to handle a memory access exception. The exception filter has the responsibility for examining the situation and returning the appropriate value.
This code demonstrates a method for identifying the kind of exception that has occurred:
_ _try { x = 0; y = 4 / x; } _ _except ((GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { // Handle divide by zero exception. } |
The GetExceptionCode intrinsic function returns a value identifying the kind of exception that has occurred:
DWORD GetExceptionCode(); |
The following list of all predefined exceptions and their meanings is adapted from the Platform SDK documentation. The exception identifiers can be found in the WinBase.h file. I have grouped the exceptions together by category.
The GetExceptionCode intrinsic function can be called only in an exception filter (between the parentheses following _ _except) or inside an exception handler. The following code is legal:
_ _try { y = 0; x = 4 / y; } _ _except ( ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) || (GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO)) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { switch (GetExceptionCode()) { case EXCEPTION_ACCESS_VIOLATION: // Handle the access violation. break; case EXCEPTION_INT_DIVIDE_BY_ZERO: // Handle the integer divide by 0. break; } } |
However, you cannot call GetExceptionCode from inside an exception filter function. To help you catch such errors, the compiler will produce a compilation error if you try to compile the following code:
_ _try { y = 0; x = 4 / y; } _ _except (CoffeeFilter()) { // Handle the exception. } LONG CoffeeFilter (void) { // Compilation error: illegal call to GetExceptionCode. return((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH); } |
You can get the desired effect by rewriting the code this way:
_ _try { y = 0; x = 4 / y; } _ _except (CoffeeFilter(GetExceptionCode())) { // Handle the exception. } LONG CoffeeFilter (DWORD dwExceptionCode) { return((dwExceptionCode == EXCEPTION_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH); } |
Exception codes follow the rules for error codes as defined inside the WinError.h file. Each DWORD is divided as shown in Table 24-1.
Table 24-1. The composition of an error code
Bits | 31-30 | 29 | 28 | 27-16 | 15-0 |
---|---|---|---|---|---|
Contents | Severity | Microsoft/customer | Reserved | Facility code | Exception code |
Meaning | 0=Success 1=Informational 2=Warning 3=Error | 0=Microsoft-defined code 1=customer-defined code | Must be 0 | Microsoft-defined (see table below) | Microsoft/customer-defined |
Currently, Microsoft defines the following facility codes.
Facility Code | Value | Facility Code | Value |
---|---|---|---|
FACILITY_NULL | 0 | FACILITY_CONTROL | 10 |
FACILITY_RPC | 1 | FACILITY_CERT | 11 |
FACILITY_DISPATCH | 2 | FACILITY_INTERNET | 12 |
FACILITY_STORAGE | 3 | FACILITY_MEDIASERVER | 13 |
FACILITY_ITF | 4 | FACILITY_MSMQ | 14 |
FACILITY_WIN32 | 7 | FACILITY_SETUPAPI | 15 |
FACILITY_WINDOWS | 8 | FACILITY_SCARD | 16 |
FACILITY_SECURITY | 9 | FACILITY_COMPLUS | 17 |
So here's what we get if we pick apart the EXCEPTION_ACCESS_VIOLATION exception code. Looking up EXCEPTION_ACCESS_VIOLATION in WinBase.h, we see that it has a value of 0xc0000005:
C 0 0 0 0 0 0 5 (hexadecimal) 1100 0000 0000 0000 0000 0000 0000 0101 (binary) |
Bits 30 & 31 are both set to 1, indicating that an access violation is an error (the thread cannot continue running). Bit 29 is 0, meaning that Microsoft has defined this code. Bit 28 is 0 because it is reserved for future use. Bits 16 through 27 are 0, indicating FACILITY_NULL (an access violation can happen anywhere in the system; it is not an exception that only occurs when using certain facilities). Bits 0 through 15 contain the value 5, which just means that Microsoft defined an access violation as code 5.