该异常已处理完,接着继续执行except程序段后的代码。
EXCEPTION_CONTINUE_EXECUTION表明当一个异常出现时,运行程序不立即执行except程序段内的代码而返回try程序段内产生异常的语句继续执行该语句。
EXCEPTION_CONTINUE_SEARCH表明当一个异常出现时,运行程序不执行该except程序段内的代码而寻求由高一级的异常处理句柄来处理此异常。
Win32 WINBASE.H头文件中定义了可能出现的各种异常代码。我们可以通过调用GetExceptionCode函数来诊断何种异常被提出,从而决定异常处理句柄该采取何种行动。GetExceptionCode函数定义为
DWORD GetExceptionCode(VOID);
它的返回值表明何种异常出现。下面的程序说明如何调用GetExceptionCode函数。
__try {
x = 0;
y = 4 / x;
}
__except ((GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Handle divide by zero exception.
}
当一个异常发生时,操作系统会将有关该异常的信息储存在三个结构中,并将它们存放在提出此异常线程的堆栈里。这三个结构是EXCEPTION_RECORD,CONTEXT,和EXCEPTION_POINTERS。EXCEPTION_RECORD储存着与CPU无关的异常信息,CONTEXT则储存着与CPU有关的异常信息。EXCEPTION_POINTERS结构包含了两个分别指向EXCEPTION_RECORD和CONTEXT的指针。
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS
假如你的程序需要这些异常信息,你可以通过调用GetExceptionInformation函数来获取。
LPEXCEPTION GetExceptionInformation(void);
GetExceptionInformation函数返回一个指向EXCEPTION_POINTERS结构的指针。下面的函数说明了如何调用GetExceptionInformation函数。
void FuncSkunk (void) {
// Declare variables that we can use to save the exception
// record and the context if an exception should occur.
EXCEPTION_RECORD SavedExceptRec;
CONTEXT SavedContext;
.
.
.
__try {
.
.
.
}
__except (
SavedExceptRec =
*(GetExceptionInformation())->ExceptionRecord,
SavedContext =
*(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
// We can use the SavedExceptRec and SavedContext
// variables inside the handler code block.
switch (SavedExceptRec.ExceptionCode) {
.
.
.
}
}
.
.
.
}
注意,在上面的异常筛选表达式程序中我们使用了C语言的“,”操作符。许多程序员对此并不是很熟悉。该操作符告诉编译器从左到右运行由“,”分离的各表达式。在所有的表达式都运行完后,返回最后一个(或最右面的)表达式的值。
4、软件异常(software exception)
至此为止我们所讨论的是如何处理由CPU提出的硬件异常(hardware exception)。通常,操作系统或应用程序自身提出的软件异常也非常有用。例如,HeapAlloc函数就提供了一个非常好的利用软件异常的例子。在调用HeapAlloc时,你可以设置HEAP_GENERATE-EXCEPTIONS指示旗(flag)。这样如果HeapAlloc不能满足你的内存分配要求,它会产生一个STATUS_NO_MEMORY软件异常。
假如你想利用这个异常,你可以在你的try程序段内继续编写你的代码,如同内存分配总是会成功一样。如果内存分配失败,你可以利用except程序段来处理这个异常或利用finally程序段来做清除工作。
你的程序不需要知道你要处理的异常是软件异常还是硬件异常。你利用try-finally和try-except来处理软件异常和硬件异常的方式是一样的。但是你可以让你的程序象HeapAlloc函数一样提出自己的异常。为了在你的程序中提出软件异常,你需要调用RaiseException函数。
VOID RaiseEx