Filtering Structured Exceptions (C++)
Go Up to Structured Exceptions Under Win32 (C++)
A filter expression can invoke a filter function but the filter function cannot call GetExceptionInformation. You can pass the return value of GetExceptionInformation as a parameter to a filter function.
To pass the EXCEPTION_POINTERS information to an exception handler, the filter expression or filter function must copy the pointer or data from GetExceptionInformation to a location where the handler can later access it.
In the case of nested try-except statements, each statement's filter expression is evaluated until it locates EXCEPTION_EXECUTE_HANDLER or EXCEPTION_CONTINUE_EXECUTION. A filter expression can invoke GetExceptionInformation to get exception information.
As long as GetExceptionInformation or GetExceptionCode is called directly in the expression provided to __except, you can use a function to determine what to do with an exception rather than trying to create a complex C++ expression. Almost all of the information needed to handle an exception can be extracted from the result of GetExceptionInformation. GetExceptionInformation returns a pointer to an EXCEPTION_POINTERS structure:
struct EXCEPTION_POINTERS {
EXCEPTION_RECORD *ExceptionRecord;
CONTEXT *Context;
};
EXCEPTION_RECORD contains the machine-independent state:
struct EXCEPTION_RECORD {
DWORD ExceptionCode;
DWORD ExceptionFlags;
struct EXCEPTION_RECORD *ExceptionRecord;
void *ExceptionAddress;
DWORD NumberParameters;
DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
};
Typically, the filter function looks at the information in the ExceptionRecord to decide how to respond. Sometimes more specific information is needed (especially if the action to take is EXCEPTION_CONTINUE_EXECUTION: if nothing is done, the code that caused the exception would be executed again). For this situation, the other field of the EXCEPTION_POINTERS structure provides the processor state at the time of the exception. If this structure is modified and the filter returns EXCEPTION_CONTINUE_EXCEPTION, it is used to set the state of the thread before continuing with execution. For example:
static int xfilter(EXCEPTION_POINTERS *xp) {
int rc;
EXCEPTION_RECORD *xr = xp->ExceptionRecord;
CONTEXT *xc = xp->Context;
switch (xr->ExceptionCode) {
case EXCEPTION_BREAKPOINT:
// whoops, someone left an embedded breakpoint.
// just step over it (1 byte on x86)
++xc->Eip;
rc = EXCEPTION_CONTINUE_EXECUTION;
break;
case EXCEPTION_ACCESS_VIOLATION:
rc = EXCEPTION_EXECUTE_HANDLER;
break;
default:
// give up
rc = EXCEPTION_CONTINUE_SEARCH;
break;
};
return rc;
}
// ...
EXCEPTION_POINTERS * xp;
try {
func();
}
__except (xfilter(xp = GetExceptionInformation())) {
abort();
}