细说windows的异常处理和实现——结构化异常

异常与C++的异常

C++编程中有一个重要的机制就是异常的处理,标准的C++定义了try...catch..throw的异常处理机制。但是这只是C++里的异常。

 

广义的异常可以分为硬件产生的异常软件产生的异常,像throw这样的动作就是在软件上产生一个异常,但是像写入一个非法内存、除0这些都是硬件产生的异常;

异常的处理可以分为结构化异常处理(Structured Exception Handling)SEH和向量异常处理(Vectored exception handling)VEH

 

C++里try...catch..throw属于SEH,但是他只能捕捉显示的throw出来的软件异常,明确这个问题非常重要。以前一直认为可以catch任何异常,其实这种想法是错的,比如写一句int* p=0;*p=1;这样的语句是catch不到的,直接就会crash了,因为这是内存错误,硬件异常。

 

这样看来,C++的try...catch..throw异常处理机制只是处理了所有异常中的一个子集而已。

然而在windows上开发的我们,尤其是去开发一些产品,我们希望有方法去处理任何异常,绝不让用户突然收到一个崩溃的感叹号,提高用户的体验怎么办?

原来window在系统层面上提供了更多的异常的处理机制,而C++的try...catch..throw也只是window系统的异常处理机制中被整合进去的一小块。

 

window系统层面的(结构化)异常处理机制

window是把所有的硬件和软件的异常都整合起来同等看待,无论是内存错误、用throw产生一个异常,都会触发操作系统对当前的线程的异常处理

每个线程在创建后,都会初始化一个数据结构:

 ;struct _EXCEPTION_REGISTRATION{
 ;     struct _EXCEPTION_REGISTRATION *prev;
 ;     void (*handler)(PEXCEPTION_RECORD,
 ;                     PEXCEPTION_REGISTRATION,
 ;                     PCONTEXT,
 ;                     PEXCEPTION_RECORD);
 ;     struct scopetable_entry *scopetable;
 ;     int trylevel;
 ;     int _ebp;
 ;     PEXCEPTION_POINTERS xpointers;
 ;}

 

很多个EXCEPTION_REGISTATION 连成一个list L

其中的每个节点包含了一个handler成员,他就是具体的对异常进行处理的操作(可以猜测catch后的内容就是最终被整合到这个函数里的)

当一个异常E发生后,系统会寻找这个线程的L,从头开始,知道寻找到能对E进行处理的那个节点EXCEPTION_REGISTATION,对其进行处理。

对于C++的try catch其实就是在try的时候将L里面建立一个新的节点,用于捕捉某个异常。

 

所以win的异常处理机制的核心就在于每个线程内的这个EXCEPTION_REGISTATION 的list。

 

这里有个问题,就是当一个异常没有再list寻找到相应的节点怎么办,其实这个list会在尾端放置一个默认的异常处理单元,当查询到尾端时就一定调用这个处理函数。

所以我们就有一种办法去截获所有程序中我们无法catch的异常(硬件或软件),就是去自定义这个处理函数,使用API  SetUnhandledExceptionFilter

 

万能的异常捕获器 SetUnhandledExceptionFilter

记住这个函数只有在release版本生效!

win程序在release情况下,发生了异常,并且没有被捕捉处理,就会调用一个默认的UnhandledExceptionFilter函数,这个函数还传入一个参数_EXCEPTION_POINTERS*,里面有crash的一些信息。


如果我们想自定义这个处理方法,就可以自定一个函数如

 long __stdcall MyUnhandledExceptionFilter (_EXCEPTION_POINTERS* ExceptionInfo){。。。

}

然后使用SetUnhandledExceptionFilter set进来。

MyUnhandledExceptionFilter 函数有三种返回值:

EXCEPTION_EXECUTE_HANDLER equ 1 表示我已经处理了异常,可以结束了,这时执行完这个函数程序退出
EXCEPTION_CONTINUE_SEARCH equ 0 表示我不处理,其他人来吧,于是windows调用默认的处理程序显示一个错误框,并结束
EXCEPTION_CONTINUE_EXECUTION equ -1 表示错误已经被修复,请从异常发生处继续执行  ,这时程序会试图在运行一遍刚才又问题的代码

 

通过自定义的异常处理函数,等于截获了程序出错的最后一道屏障,在程序crash即将关闭前改变了原有的行为,可以做到:

1.可以dump出来当前的信息,上传给服务器用于技术人员统计分析

2.可以用更加友善的界面告诉你的用户程序出错了,优雅的挂掉



 


转载于:https://www.cnblogs.com/weizhixiao/archive/2013/04/27/5697319.html

你可能感兴趣的:(细说windows的异常处理和实现——结构化异常)