Windows 核心编程第五版学习笔记(五)
第23章 终止处理程序
1、
__try
{
被保护代码
}
__finally
{
终止处理程序。
}
__try和__finally关键字标记了终止处理程序的两个部分(被保护代码和终止处理程序),前面这段代码中,操作系统和编译器的协同工作保证了不管被保护代码部分是如何退出的(除非调用ExitProcess, ExitThread, TerminateProcess, TerminateThread来终止进程或程序)终止处理程序都会被调用,即__finally代码块都会被执行。
1、 尽管绝大多数情况下,try块中的提前退出都会被终止程序所捕获,但是在进程或程序被提前终止的情况下,系统没法保证finally代码块的执行,调用ExitThread或者ExitProcess可以马上终止线程或进程,而不会引发finally代码块的执行,同样,如果当前进程或线程因为另一个程序调用TerminateProcess或者TerminateThread而不得不结束,finally代码块也不会被执行,有一些C运行函数(abort)因为其内部最终调用的是ExitProcess,也不会导致finally代码块的执行,我们没法阻止别的线程"杀死"我们的线程或进程,但是可以在自己的代码中尽量避免对ExitThread或者ExitProcess的草率调用。
2、 不要在终止处理程序里包含让try块提前退出的语句,这意味着从try块和finally块中移除return、continue、break、goto语句,为了帮助我们尽可能避免写出让try块提前退出的代码,Microsoft加入了__leave关键字,这个关键字导致代码执行控制流跳到try块的结尾,代码执行将正常地从try块进入到finally块,所以不会产生任何额外开销。
第24章 异常处理程序与软件异常
1、当一个硬件或者软件异常被抛出时,操作系统会给我们的应用程序一个查看异常类型的机会,并允许应用程序自己处理这个异常。
__try
{
}
__exception(exception filter)
{
}
任何时候创建一个try块,后面必须跟一个finally代码块或except代码块,但是try块后不能同时有finally块和except块,也不能同时又多个finally块或except块,不过可以将try-fianlly块嵌套在try-except块中。
2、与终止处理程序不同,异常过滤程序和异常处理程序主要由操作系统来负责执行。
尽管我强烈建议读者不要在终止处理程序的try块中使用return、goto、continue、break语句,但是在异常处理程序的try块中,这些语句不会导致程序性能损失或者增加代码量。换句话说,把这些语句置于try块中不会带来局部展开这样的额外开销。
3、异常处理程序的流程图
EXCEPTION_EXECUTE_HANDLER这个值等于告诉系统,我知道这个异常,并预计这个异常在某种情况下会产生,同时已经写了一些代码来处理它,让这些代码现在就执行吧。于是,系统执行全局展开,让程序执行跳转到except代码块处,当except代码块运行结束后,系统就会认为异常已经得到了处理,于是允许应用程序继续执行,这个机制允许Windows应用程序捕获错误,处理它们,并继续运行,用户甚至不知道曾经发生过错误。当except块中的代码执行完毕后,如果异常处理程序被指定为EXCEPTION_EXECUTE_HANDLER,代码执行从except块后的第一句代码继续执行。
当异常过滤程序的计算结果为EXCEPTION_EXECUTE_HANDLER时, 系统必须执行全局展开,全局展开导致所有已经开始执行但尚未完成的try-finally块得以继续执行,在调用栈中,这些try-finally块位于对异常进行了处理的try-except块的下方。
从windows vista开始,如果一个异常发生在try/finally块中,并在其上层又额米有try/except块(同时过滤程序返回EXEPTION_EXCUTE_HANDLER),进程就会立即终止,全局展开并不会发生,finally块也不会执行。全局展开发生在except块执行之前。
4、我们可以再异常过滤程序中添加很多代码,但是过滤程序必须返回三个异常标识符中的一个,但是它也可以执行其他我们想要它执行的任务,不管怎么样,请记住一个异常被抛出后,进程很可能已经变得不稳定,所以,最好还是让异常过滤程序中的代码相对简单,比如,在堆被破坏的情况下,在过滤程序里运行很多代码可能导致进程挂起或者不加任何提示地终止。
当异常处理程序返回结果为EXCEPTION_CONTINUE_EXECUTION时,系统会将程序的控制流跳转到导致异常的那条指令,并尝试重新执行这条指令。
4、GetExceptionCode是内在函数,它的返回值表明刚刚发生的异常的类型,我们不能在异常过滤程序的函数里调用GetExceptionCode,应该在计算异常表达式时使用。
5、当一个异常发生时,系统会向发生异常的线程的栈中压入三个结构:EXCEPTION_RECORD, CONTEXT和EXCEPTION_POINTERS,可以通过GetExceptionInformation函数得到这些信息,但是该函数只能在异常过滤程序中调用,因为哪三个数据结构只有在系统计算异常过滤程序时才是有效地,一旦程序控制流被转移到异常处理程序或别的地方,这些栈上的数据结构就被销毁了。
浙公网安备 33010602011771号