编写异常筛选器

您可以通过跳转到异常处理程序的级别或通过继续执行来处理异常。 可以使用筛选表达式来清理问题,而不是使用异常处理程序代码来处理异常并失败。 然后,通过返回 EXCEPTION_CONTINUE_EXECUTION (-1) ,可以恢复正常流,而无需清除堆栈。

注意

有些异常无法继续。 对这样的异常来说,如果筛选计算结果为 -1,则系统将产生新的异常。 调用 RaiseException 时,将确定异常是否会继续。

例如,下面的代码使用筛选表达式中的函数调用:此函数处理该问题并返回 –1 以继续正常控制流:

// exceptions_Writing_an_Exception_Filter.cpp
#include <windows.h>
int main() {
   int Eval_Exception( int );

   __try {}

   __except ( Eval_Exception( GetExceptionCode( ))) {
      ;
   }

}
void ResetVars( int ) {}
int Eval_Exception ( int n_except ) {
   if ( n_except != STATUS_INTEGER_OVERFLOW &&
      n_except != STATUS_FLOAT_OVERFLOW )   // Pass on most exceptions
   return EXCEPTION_CONTINUE_SEARCH;

   // Execute some code to clean up problem
   ResetVars( 0 );   // initializes data to 0
   return EXCEPTION_CONTINUE_EXECUTION;
}

每当筛选需要执行任何复杂操作时,最好在筛选表达式中使用函数调用。 计算表达式将导致函数的执行,在此示例中,Eval_Exception

请注意使用 GetExceptionCode 确定异常。 必须在 __except 语句的筛选表达式内调用此函数。 Eval_Exception 不能调用 GetExceptionCode,但是它必须具有传递给它的异常代码。

除非异常是整数或浮点溢出,否则此处理程序会将控制权传递给其他处理程序。 如果异常是整数或浮点溢出,则处理程序将调用一个函数(ResetVars 只是一个示例,不是 API 函数)以重置某些全局变量。 __except 语句块(在此示例中为空)无法执行,因为 Eval_Exception 绝不返回 EXCEPTION_EXECUTE_HANDLER (1)。

使用函数调用是处理复杂筛选器表达式的一个很好的通用方法。 其他两个有用的 C 语言功能是:

  • 条件运算符

  • 逗号运算符

条件运算符在这里通常很有用。 它可用于检查特定返回代码,然后返回两个不同值中的一个。 例如,仅当异常为 STATUS_INTEGER_OVERFLOW 时,下面代码中的筛选器才能识别异常:

__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ? 1 : 0 ) {

条件运算符在此示例中的用途主要是进行澄清,因为下面的代码将生成相同的结果:

__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ) {

条件运算符在你希望筛选器的计算结果为 –1、EXCEPTION_CONTINUE_EXECUTION 时更有用。

逗号运算符允许按顺序执行多个表达式。 然后返回最后一个表达式的值。 例如,下面的代码将异常代码存储在一个变量中,然后测试它:

__except( nCode = GetExceptionCode(), nCode == STATUS_INTEGER_OVERFLOW )

另请参阅

编写异常处理程序
Structured Exception Handling (C/C++)