__try, __except(exception filter)
一、异常过滤器(exception filter)和异常处理程序
一、异常过滤器中使用逗号(,)操作符。从左到右执行,返回最右边表达式的结果。
二、异常处理程序,在try块中可以使用return, goto, continue, break等,不会产生速度和代码规模方面的不良影响(与结束处理程序不同)。
三、过滤器(表达式的值)的标识符(只有三个):
n EXCEPTION_EXECUTE_HANDLER 1:
进行全局展开,执行except块中的异常处理代码后继续执行应用程序except后的其他代码。
n EXCEPTION_CONTINUE_EXECUTION -1:
告诉系统跳回到产生异常的指令,试图再执行一次。(你必须在异常处理程序中处理这个异常,否则产生死循环)
n EXCEPTION_CONTINUE_SEARCH 0:
告诉系统去查找前面一个except块相匹配的try块,并调用这个try块的异常处理。(用于告诉系统我们在这个except块中未处理这个异常,在C25中作了进一步的说明:如果每个过滤器都这样返回,则是未处理异常,unhandled exception,将导致线程和进程终止。)
二、获取异常代码:
DWORD GetExceptionCode(); // 在WinBase.h中预定义了所有的异常。不能在过滤器函数内部调用,合法用例:
__except(ExceptFilter(GetExceptionCode())){ …… } 或
__except( (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ) || GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH )
{ …… }
1. 与内存有关的:
n EXCEPTION_ACCESS_VIOLATION // 试图对虚拟地址读写
n EXCEPTION_DATATYPE_MISALIGNMENT // 未对齐数据I/O
n EXCEPTION_ARRAY_BOUNDS_EXCEEDED // 越界的数组
n EXCEPTION_IN_PAGE_ERROR // 页故障
n EXCEPTION_GUARD_PAGE // 对PAGE_GUARD保护属性的内存页I/O
n EXCEPTION_STACK_OVERFLOW // 栈溢出
n EXCEPTION_ILLEGAL_INSTRUCTION // 执行了无效指令
n EXCEPTION_PRIV_INSTRUCTION // 执行了当前机器模式不允许的指令
2. 与异常相关的:
n EXCEPTION_INVALID_DISPOSITION // 异常过滤器返回值非三者之一
n EXCEPTION_NONCONTINUABLE_EXCEPTION // 对不能继续的异常返回EXCEPTION_CONTINUE_EXCUTION
3. 与调试相关的:
n EXCEPTION_BREAKPOINT // 遇到断点
n EXCEPTION_SINGLE_STEP // 单步指令执行完毕
n EXCEPTION_INVALID_HANDLE // 传递无效句柄
4. 与整数相关的:
n EXCEPTION_INT_DIVIDE_BY_ZERO // 用0作除数
n EXCEPTION_INT_OVERFLOW // 结果超过整数范围
5. 与浮点数相关的:
n EXCEPTION_FLT_DENORMAL_OPERAND // 浮点操作中的一个操作数不正常(值太小)。
n EXCEPTION_FLT_DIVIDE_BY_ZERO // 用0作除数
n EXCEPTION_FLT_INEXACT_RESULT // 不能精确表示成10进制小数
n EXCEPTION_FLT_INVALID_OPERATION // 其他浮点数异常
n EXCEPTION_FLT_OVERFLOW // 大于允许的值
n EXCEPTION_FLT_STACK_CHECK // 栈溢出或下溢
n EXCEPTION_FLT_UNDERFLOW // 小于允许的值
三、异常代码构成规则(WinError.h中定义):
32 bit DWORD 值意义:
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+---+-+-+-----------------------+----------------------------------+
|Sev|C|R| Facility |
Code |
+---+-+-+-----------------------+----------------------------------+
Sev(31-30):严重性系数
C(29):0 = 微软定义;1 = 客户定义
R(28):保留 = 0
Facility(27-16):设备代码
Code(15-0):异常代码
四、获取错误信息:
P EXCEPTION_POINTERS GetExceptionInformation();// 用于获取错误信息,只能在异常过滤器中调用!
系统在发生异常的栈中放入三个结构:
n EXCEPTION_ROCORD:独立于CPU
n CONTEXT:依赖于CPU(其分析要求对于不同的CPU而特殊处理)
n EXCEPTION_POINTERS:包含两个指针,分别指向EXCEPTION_ROCORD和CONTEXT。
五、引发软件异常
VOID RaiseException(
DWORD dwExceptionCode, // 标识引发异常的值,见上
DWORD dwExceptionFlags, // 0或EXCEPTION_NONCONTINUABLE
DWORD nNumberOfArguments, // 附加信息,NULL
CONST ULONG_PTR *pArguments); // 附加信息,NULL