Windows结构化异常在《Windows核心编程》中有大量篇幅做了介绍,这里面介绍的内容都基于书中的内容和自己的理解与研究。其实,在windows平台下,C++和C#的异常处理都是依靠Windows的结构化异常来实现的,大家可以依靠VS Debug来查看具体的信息.
Windows结构化异常介绍
Windows的结构化异常的大量实现是有操作系统和编译器共同完成的,其主要分为终止处理(termination handling)和异常处理(exception handling)两部分。
- 终止处理程序:终止处理程序确保不管一代代码是如何退出的,梁歪一个代码块都可以(终止处理程序)都可以被执行,一般情况下确保资源的释放,终止程序的基本语法如下:
__try{
// Guarded body 可能出现异常的代码
}
__finally{
// 终止处理程序
}
- 异常处理程序: 当一个硬件或者软件异常被抛出时,windows系统会给我们的应用程序一个查看和处理异常的机会,并允许应用程序自己处理这个异常,基本代码为:
__try{
// Guarded body 可能异常处理的程序
}
__except(exception_filter){
// exception handling 异常处理函数
}
语法上需要注意的是: 任何一个__try块,后面必须跟一个finally代码块或者except代码块,但是不能同时有finally块和except块,或者同时有多个finally块或者except块。不过却可以将try-finally块嵌套到try-except块中,具体用法可以参考后面的例子程序。
如何实现结构化异常
在这里大致介绍一个结构化异常是如何实现的,要了解结构化异常怎么实现,可以参考网页:http://www.codeproject.com/Articles/2126/How-a-C-compiler-implements-exception-handling
可以介绍一下的具体的基础内容:
a) Stack Overview:函数调用堆栈
我们先看一个没有异常的函数调用堆栈, 详细看下图:
从函数的调用堆栈中,我们可以看出函数的调用关系为:foo->bar->widget.
b) EXCEPTION_REGISTRATION - 异常处理结构体
Windows 下有一个结构体为EXCEPTION_REGISTRATION ,用于保存异常的处理程序,基本的结构 :
struct EXCEPTION_REGISTRATION
{
EXCEPTION_REGISTRATION *prev;
DWORD handler;
int id;
DWORD ebp;
};
从字面上可以理解为,异常处理程序应该是通过链表组织起来。
c)Function Info
d)FS:[0]
FS 是一个线程堆栈寄存器,具体内容可以参考http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
e)Stack with exception
- 基本的代码示例
大家可以通过下面的代码体会 windows下的__try, __except, __finally EXCEPTION_EXECUTE_HANDLER, EXCEPTION_CONTINUE_SEARCH,EXCEPTION_CONTINUE_EXECUTION, 的用法。其实C#的异常处理应该是基于上述关键字实现的。
#include "stdafx.h"
#include <Windows.h>
DWORD FilterFunction()
{
printf("1 "); // printed first
//return EXCEPTION_EXECUTE_HANDLER;
//return EXCEPTION_CONTINUE_SEARCH;
return EXCEPTION_CONTINUE_EXECUTION;
}
int _tmain(int argc, _TCHAR* argv[])
{
__try
{
__try
{
RaiseException(
1, // exception code
0, // continuable exception
0, NULL); // no arguments
printf("4\n"); // this is printed last
}
__finally
{
printf("2 "); // this is printed second
}
}
//__except (EXCEPTION_CONTINUE_SEARCH)
//{
// printf("Test\n"); // this is printed last
//}
__except ( FilterFunction())
{
printf("3\n"); // this is printed last
}
return 0;
}
异常与调试器
对于下列windows的错误报告,你能想到什么:
其实是windows Error Report中增加了调试的支持,具体的内容请查看下面流程图(来自《windows核心编程):
在讨论Windows Error Report的处理流程前,请看下面的用调试器等到的调用堆栈:
在这里要讨论具体的UnhandledExceptionFilter函数的处理大致流程如下:
1)将未处理的异常报告通知给调试器
UnhandledExceptionFilter函数首先检查当前程序是不是在调试器的控制下,如果是,将通知调试器,调试器根据通知的消息定位代码与调用堆栈。
2) 通知给我们设置的全局异常过滤函数
如果应用程序已经调用SetUnhandledExceptionFilter,其会调用该函数,一般来讲,该函数可以用于保存堆栈信息,以便于调试和解决问题。
3)将未处理的异常再次报告给调试器
4)终止进程
具体详细的内容,请参考 《Windows 核心编程》 一书。