第2 3章 结束处理程序

SEH(结构化异常处理)

S E H的好处就是当你编写程序时,只需要关注程序要完成的任务。

如果在运行时发生什么错误,系统会发现并将发生的问题通知你。利用S E H,你可以完全不用考虑代码里是不是有错误,这样就把主要的工作同错误处理分离开来。这样的分离,可以使你集中精力处理眼前的工作,而将可能发生的错误放在后面处理。

实际包含两个主要功能:结束处理( termination handling)和异常处理( e x c e p t i o nh a n d l i n g)。本章讨论结束处理,下一章讨论异常处理。

:不要将结构化异常处理同C + +的异常处理相混淆。C + +异常处理是一种不同形

式的异常处理,其形式是使用C + +关键字c a t c h和t h r o w。最后再区分这两个的区别。

下面是基本调用样子:

 

Windows核心编程 第23章 结束处理程序_处理程序

- - t r y和- - f i n a l l y关键字用来标出结束处理程序两段代码的轮廓。在上面的代码段中,操作系统和编译程序共同来确保结束处理程序中的 - - f i n a l l y代码块能够被执行,不管保护体( t r y块)是如何退出的。不论你在保护体中使用

要完成这些事情,编译程序必须生成附加的代码,系统要执行额外的工作。在不同的C P U上,结束处理所需要的步骤也不同。例如,在 A l p h a处理器上,必须执行几百个甚至几千个C P U指令来捕捉t r y块中的过早返回并调用f i n a l l y块。在编写代码时,就应该避免引起结束处理程序的t r y块中的过早退出,因为程序的性能会受到影响。

注意当控制流自然地离开t r y块并进入f i n a l l y块(就像在F u n c e n s t e i n 1中)时,进入f i n a l l y块的系统开销是最小的。在x86 CPU上使用微软的编译程序,当执行离开 try 块进入f i n a l l y块时,只有一个机器指令被执行。

常用举例:

1.

Windows核心编程 第23章 结束处理程序_异常处理_02

会弹出崩溃框,但是点击关闭后会执行finally代码,但是不会执行第二个messagebox:

Windows核心编程 第23章 结束处理程序_控制流_03

Windows核心编程 第23章 结束处理程序_异常处理_04

2.下面这个函数返回14,自己好好理解下:

Windows核心编程 第23章 结束处理程序_异常处理_05

3.下面这个,按照书上的意思是返回2,然而是没编译过去(vs2012 C++)

 

Windows核心编程 第23章 结束处理程序_异常处理_06

4.书上写了三个函数,同功能,直接截图过来了

(1)

Windows核心编程 第23章 结束处理程序_处理程序_07

(2)

Windows核心编程 第23章 结束处理程序_处理程序_08

(3)

Windows核心编程 第23章 结束处理程序_异常处理_09

5.最终的边界

t r y块中使用r e t u r n语句,微软在其C / C + +编译程序中增加了另一个关键字- -l e a v e。这里是F u n c a r m a 4版,它使用了- - l e a v e关键字:

 如果直接这样:

那么return导致的进入finally的状态不是流入的,也就是需要很多辅助代码来处理,如果直接使用__leave

Windows核心编程 第23章 结束处理程序_控制流_10

那就是类似如下优化:

Windows核心编程 第23章 结束处理程序_异常处理_11

从而优化了执行时间。
关于f i n a l l y块的说明

已经明确区分了强制执行f i n a l l y块的两种情况:

• 从t r y块进入f i n a l l y块的正常控制流。

• 局部展开:从t r y块的过早退出(g o t o、l o n g j u m p、c o n t i n u e、b r e a k、r e t u r n等)强制控制转移到f i n a l l y块。

global unwind),在发生的时候没有明显的标识,我们在本章前面F u n c f u r t e r 1函数中已经见到。在F u n c f u r t e r 1的t r y块中,有一个对F u n c i n a t o r函数的调用。如果F u n c i n a t o r函数引起一个内存访问违规( memory access violation),一个全局展开会使F u n c f u r t e r 1的f i n a l l y块执行。下一章将详细讨论全局展开。

由于以上三种情况中某一种的结果而导致f i n a l l y块中的代码开始执行。为了确定是哪一种情况引起f i n a l l y块执行,可以调用内部函数(或内蕴函数,intrinsic function)Abnormal Te r m i n a t i o n:

BOOL AbnormalTermination();

这个内部函数只在f i n a l l y块中调用,返回一个B o o l e a n值。指出与f i n a l l y块相结合的t r y块是否过早退出。换句话说,如果控制流离开 t r y块并自然进入f i n a l l y块,A b n o r m a l Te r m i n a t i o n将返回FA L S E。如果控制流非正常退出 t r y块 — 通常由于g o t o、r e t u r n、b r e a k或c o n t i n u e语句引起的局部展开,或由于内存访问违规或其他异常引起的全局展开 — 对A b n o r m a l Te r m i n a t i o n的调用将返回T R U E。没有办法区别f i n a l l y块的执行是由于全局展开还是由于局部展开。但这通常不会成为问题,因为可以避免编写执行局部展开的代码。

使用结束处理程序的理由:

• 简化错误处理,因所有的清理工作都在一个位置并且保证被执行。

• 提高程序的可读性。

• 使代码更容易维护。

• 如果使用得当,具有最小的系统开销。

Try和__Try区别:

异常处理

 

Windows核心编程 第23章 结束处理程序_处理程序_12

结果是输出两个对话框,没有崩溃界面。

Windows核心编程 第23章 结束处理程序_控制流_13

SEH

Windows核心编程 第23章 结束处理程序_处理程序_14

结果是先输出一个崩溃页面,点击关闭,弹出matk1对话框。

Windows核心编程 第23章 结束处理程序_处理程序_15

 

Windows核心编程 第23章 结束处理程序_处理程序_16