看看一个程序发生错误后,Windows是如何结合SEH机制进行处理的。
1.因为有多种异常,系统首先判断异常是否应发送给目标程序,如果应该发送,并且目标程序正处于被调试状态,则系统挂起程序,填写如下结构:
typedef struct _EXCEPTION_DEBUG_INFO {
EXCEPTION_RECORD ExceptionRecord;
DWORD dwFirstChance;
} EXCEPTION_DEBUG_INFO, *LPEXCEPTION_DEBUG_INFO;
将成员
dwFirstChance置为1,并向调试器发送
EXCEPTION_DEBUG_EVENT 消息。剩下的事情就由调试器全权负责了,调试器可能处理这个异常,也可能无法处理。
2.如果调试器未能处理异常或程序根本没有被调试,系统就会查找是否存在与线程相关的异常处理过程,如果目标程序中存在与线程相关的异常处理过程,系统就会调用程序的线程相关的SEH异常处理。
3.与线程相关的异常处理过程可以有一个或多个,每个可以选择处理或者不处理异常,如果它不处理并且存在多个线程相关的异常处理过程,可交由链起来的其他异常处理过程进行处理,以此类推。
4.如果程序线程的异常处理均选择不处理异常,如果程序处于被调试状态,操作系统仍会再次挂起程序通知调试器,这次EXCEPTION_DEBUG_INFO 结构的dwFirstChance成员置为0
5.如果程序未处于被调试状态或者调试器任然未能处理,并且程序调用了API函数SetUnhandledExceptionFilter设置了与进程相关的异常处理过程的话,系统转向对它的调用。
6.如果程序没有设置进程相关的异常处理过程或者进程相关的异常处理过程也未能处理这个异常,系统会调用默认的系统异常处理程序,通常显示一个对话框(类似于应用程序错误),可以选择“确定”或者最后将其附加到调试器上的”取消“按钮。如果没有调试器能被附加于其上或调试器还是处理不了异常,系统就会调用ExitProcess终结程序。
7.不过在终结之前,系统再次调用发生异常的线程中所有的异常处理过程,这是线程异常处理过程获得的最后清理未释放资源的机会,其后程序就终结了。
学习SEH要树立一个最基本的观念:SEH是系统发现异常或错误时,在终结应用程序之前给应用程序的一个最后改正错误的机会,从程序设计的角度说,就是系统在终结程序之前给程序的一个执行其预设定的回调函数的机会。
上面一段文字看着有点晕,主要是有些概念不清楚,我们把SEH分下类就可以了。
一般SEH可分为两类:一类是监视某线程中某段代码是否发生异常的异常处理过程,一般称为线程相关的异常处理过程;
另一类是监视整个进程中所有线程是否发生议程的异常处理过程,称为进程相关的异常处理过程,也有人称为筛选器。
总结一下:当程序发生异常的时候,如果在调试状态下,调试器会接管我们的异常,调试器来处理。如果没有处理成功或者是没有在调试情况下,系统会首先查找我们自己写的相关的异常处理程序(这个是线程相关的),如果这个线程处理程序没有处理,会交给其他链起来的相关异常处理线程,一直类推下去,直到解决(如果没有解决,下面另述),这个就像我们写java程序的时候,我们不想考虑一些异常,就把这些异常一层一层的往上抛,最后交给系统。
当线程处理异常程序没有解决的话,现在再看一下它是否处于调试状态,如果还没有解决的话,如果我们自己设置了进程相关的处理程序,系统会转向这里进行处理。
如果还没有解决,现在就不是我们可以操纵的了,系统会调用系统的异常处理,直接把这个错误给我们显示出来,效果就是一个提示框~,然后终止程序,在此之前调用前面的所有异常处理,释放资源。