WIN32汇编语言教程:第14章 异常处理 · 14.1 异常处理的用途
对程序执行中的异常(Exception)大家都不陌生,先来回顾一下DOS操作系统对异常的处理方法。在DOS操作系统中,当操作系统在运行中发生“异常”时,会去调用INT 24h中断,系统默认的INT 24h中断处理程序会将出错代码翻译成文本信息显示在屏幕上,然后让用户选择“Ignore”,“Retry”,“Fail”或者“Abort”,并根据用户的输入结果来选择不同的操作——忽略异常、重试产生异常的操作或者强行终止程序的执行。
系统默认的异常处理方法有时候不是很合适,比如对于在图形方式下运行的DOS程序来说,系统显示的出错信息会破坏屏幕的美观;另外,程序可能希望不要向用户提供“Abort”选项来保证程序不会因为一些微不足道的错误而被终止。为了处理这些情况,程序可以用自定义的异常处理程序来替换系统默认的处理程序,而这是很容易实现的——由于DOS系统在检测到异常的时候仅仅去调用24h号中断并根据中断的返回值决定下一步的处理方式,只要应用程序截获INT 24h中断,就可以在自己提供的中断服务程序中按照自己的意图决定系统处理异常的走向。
Windows操作系统对异常的处理流程相对比较复杂,与DOS操作系统相比,最大的区别在于DOS的异常处理是被动的,一般仅用来处理操作系统内部的异常,对于其他层次的异常是无法处理的,比如使用INT 21h去读盘的时候发生错误会激发INT 24h中断,但在BIOS服务程序级别用INT 13h去读盘时发生错误就不会激发INT 24h中断,对应用程序胡作非为引发的异常更是束手无策;而Windows的异常处理机制是依靠80x86处理器的保护机制来主动捕获异常,所以Win32下异常处理程序的用途不仅仅局限于防止程序被Windows野蛮地终止,合理利用它们可以让有些功能的实现方式变得更加简单,一般来说,可以在下面这些情况下使用异常处理程序:
● 用来处理非致命的错误
程序执行中发生某些异常时只需要终止发生异常的模块(或子程序),并没有必要终止整个程序的运行,这时可以在异常处理程序中指定让程序转移到一个“安全”的地方去执行,并在这里完成资源释放、删除临时文件、显示错误提示等扫尾工作后从出错模块返回。
● 处理“计划内”的异常
程序中的有些功能本来就是设计在异常处理模块中实现的。Windows系统中虚拟内存的实现就是一个绝好的例子(如图1.5所示),第10章中介绍的内存映射文件也是以同样的方法实现的。在这些情况下,“异常”是作为一个触发条件使用的。
另外,在Windows API中使用异常处理程序进行参数的合法性检测也是很常见的。一般来说,大部分子程序都需要对输入的参数进行合法性检测,特别是对于指针类型的参数,但是当参数涉及的数据结构太复杂的时候,合法性检测会大大降低程序的效率,这时可以假定参数全部合法并尝试直接使用这些参数,如果异常处理程序没有捕获到错误,那么表示参数是合法的,这样要比在每个步骤中检测参数(或操作结果)的合法性要简洁得多。
● 处理致命错误
虽然捕获到致命错误的时候终止程序是最好的选择,但是程序在退出之前,可以在异常处理程序中进行释放资源、删除临时文件等操作,甚至可以详细记录产生异常的指令位置和环境,以便用来分析产生异常的原因。
显然,Windows中的用户自定义的异常处理函数不会再以INT 24h的方式被调用,读者也可以猜到它必定会以“回调函数”的方式来实现,但是如何写回调函数,回调函数的参数是什么,在什么地方定义回调函数呢?接下来将介绍这些内容。
上页:第13章 进程控制 · 13.4 进程的隐藏(5) 下页:第14章 异常处理 · 14.2 使用筛选器处理异常(1)