在所有 Win32 操作系统提供的机制中,使用最广泛的未公开的机制恐怕就要数结构化异常处理(structured exception handling,SEH)了。一提到结构化异常处理,可能就会令人想起 _try、_finally 和 _except 之类的词儿。在任何一本不错的 Win32 书中都会有对 SEH 详细的介绍。甚至连 Win32 SDK 里都对使用 _try、_finally 和 _except 进行结构化异常处理作了完整的介绍。既然有这么多地放都提到了 SEH,那我为什么还要说它是未公开的呢?本质上讲,Win32
结构化异常处理是操作系统提供的一种服务。编译器的运行时库对这种服务操作系统实现进行了封装,而所有能找到的介绍 SEH 的文档讲的都是针对某一特定编译器的运行时库。关键字 _try、_finally 和 _except 并没有什么神秘的。微软的 OS 和编译器定义了这些关键字以及它们的行为。其它的 C++ 编译器厂商也只需要尊从它们定好的语义就行了。在编译器的 SEH 层减少了直接使用纯操作系统的 SEH 所带来的危害的同时,也将纯操作系统的 SEH 从大家的面前隐藏了起来。 ——Matt
Pietrek
以下列出一些Win32常见的异常。
Value |
Macro | Meaning |
0x80000002 | EXCEPTION_DATATYPE_MISALIGNMENT | The thread tried to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on. |
0x80000003 | EXCEPTION_BREAKPOINT | A breakpoint was encountered. |
0xc0000005 | EXCEPTION_ACCESS_VIOLATION | The thread tried to read from or write to a virtual address for which it does not have the appropriate access. |
0xc0000006 | EXCEPTION_IN_PAGE_ERROR | The thread tried to access a page that was not present, and the system was unable to load the page. For example, this exception might occur if a network connection is lost while running a program over the network. |
0xc000001d | EXCEPTION_ILLEGAL_INSTRUCTION | The thread tried to execute an invalid instruction. |
0xc0000025 | EXCEPTION_NONCONTINUABLE_EXCEPTION | The thread tried to continue execution after a noncontinuable exception occurred. |
0xc0000026 | EXCEPTION_INVALID_DISPOSITION | An exception handler returned an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception. |
0xc000008c | EXCEPTION_ARRAY_BOUNDS_EXCEEDED | The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking. |
0xc000008d | EXCEPTION_FLT_DENORMAL_OPERAND | One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value. |
0xc000008e | EXCEPTION_FLT_DIVIDE_BY_ZERO | The thread tried to divide a floating-point value by a floating-point divisor of zero. |
0xc000008f | EXCEPTION_FLT_INEXACT_RESULT | The result of a floating-point operation cannot be represented exactly as a decimal fraction. |
0xc0000090 | EXCEPTION_FLT_INVALID_OPERATION | This exception represents any floating-point exception not included in this list. |
0xc0000091 | EXCEPTION_FLT_OVERFLOW | The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type. |
0xc0000092 | EXCEPTION_FLT_STACK_CHECK | The stack overflowed or underflowed as the result of a floating-point operation. |
0xc0000093 | EXCEPTION_FLT_UNDERFLOW | The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type. |
0xc0000094 | EXCEPTION_INT_DIVIDE_BY_ZERO | The thread tried to divide an integer value by an integer divisor of zero. |
0xc0000095 | EXCEPTION_INT_OVERFLOW | The result of an integer operation caused a carry out of the most significant bit of the result. |
0xc0000096 | EXCEPTION_PRIV_INSTRUCTION | The thread tried to execute an instruction whose operation is not allowed in the current machine mode. |
0xc00000fd | EXCEPTION_STACK_OVERFLOW | The thread used up its stack. |
如果要像处理C++类型的异常一样的处理Win32异常,即可以catch到某一类型的异常。_set_se_translator提供了这种转化的功能。以下是一个代码示例:
void trans_fuc(unsigned int, EXCEPTION_POINTERS*); class CWin32Exception { public: CWin32Exception(unsigned int n, PEXCEPTION_POINTERS pException) : m_nSE(n), m_pException(pException) {} /// 获得结构化异常信息。 PEXCEPTION_POINTERS ExceptionInformation() { return m_pException; } /// 获得结构化异常代码。 DWORD ExceptionCode() { if(NULL != m_pException) return m_nSE; else return 0; } private: /// 结构化异常代码 unsigned int m_nSE; /// 结构化异常信息 PEXCEPTION_POINTERS m_pException; }; /// 将Win32结构化异常翻译为C++异常的转换函数。 void trans_fuc(unsigned int u, EXCEPTION_POINTERS* pExp) { throw CWin32Exception(u, pExp); } 使用该代码的方式如下: // 设置异常处理转换函数 _set_se_translator(trans_fuc); // 运行测试异常 try { /*int y = 3; int x = 4; x = x - x; int z = y / x;*/ int *pTest = NULL; *pTest = 8; } catch( CWin32Exception& Win32Ex ) { PEXCEPTION_POINTERS pEx = NULL; pEx = Win32Ex.ExceptionInformation(); if (pEx->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { //处理异常代码 } }