找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 3942|回复: 0

让程序在崩溃时体面的退出之SEH -|starlee

[复制链接]
发表于 2011-12-17 22:43:16 | 显示全部楼层 |阅读模式
SEH的全称是Structured Exception Handling,是Windows操作系统提供的一种异常处理方式。SEH是属于操作系统的特性,不为特定语言设计,从它的名字就能看出它是一种结构化的异常处理方式。SEH包括了2个部分:终止处理__try/__finally和异常处理__try/__except,下面分别进行介绍。
终止处理__try/__finally
__try/__finally可以保证无论try块内的代码执行结果如何,finally块内的代码总会被调用和执行。现在用下面的这个VC++中的控制台程序来说明。
  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3.         __try
  4.         {
  5.                 MessageBox(NULL, _T("Message from '__try' section"), _T("Test"), MB_OK);
  6.                 // 除零,人为的使程序崩溃
  7.                 //
  8.                 int i = 13;
  9.                 int j = 0;
  10.                 int m = i / j;
  11.         }
  12.         __finally
  13.         {
  14.                 // 在这里添加处理程序崩溃情况的代码
  15.                 //
  16.                 // 这里以弹出一个对话框为例子
  17.                 //
  18.                 MessageBox(NULL, _T("Message from '__finally' section"), _T("Test"), MB_OK);
  19.         }
  20.         MessageBox(NULL, _T("Funcation completed"), _T("Test"), MB_OK);
  21.         return 0;
  22. }
复制代码
编译上面的代码。运行生成的EXE,会弹出下面的对话框。

点击OK按钮后,程序会崩溃。

在出现上面这个对话框的时候点击Cancel,将控制权返还给程序,那么下面的对话框就会弹出。

点击OK按钮后,程序正常退出。
由上面的例子可以看出,无论try块中的代码会不会出现异常,在程序终止的时候,finally块中的代码都会被调用和执行。所以一般情况下,finally块中的代码都是用来做一些清理工作和资源的释放。
异常处理__try/__except
__try/__except是用来捕捉异常的,只有当try块中的代码出现异常的时候,except块中的代码才会被调用和执行。它的语法是这样的:
  1. __try
  2. {
  3.         // guarded code
  4. }
  5. __except(expression)
  6. {
  7.          // exception handler code
  8. }
复制代码
它最大的一个好处就是可以完全控制异常进程。expression的值决定了异常被处理完后,进程该如何执行。下面依然用VC++中的控制台程序来说明。
  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3.         __try
  4.         {
  5.                 MessageBox(NULL, _T("Message from '__try' section"), _T("Test"), MB_OK);
  6.                 // 除零,人为的使程序崩溃
  7.                 //
  8.                 int i = 13;
  9.                 int j = 0;
  10.                 int m = i / j;
  11.         }
  12.         __except(EXCEPTION_EXECUTE_HANDLER)
  13.         {
  14.                 // 在这里添加处理程序崩溃情况的代码
  15.                 //
  16.                 // 这里以弹出一个对话框为例子
  17.                 //
  18.                 MessageBox(NULL, _T("Message from '__except' section"), _T("Test"), MB_OK);
  19.         }
  20.         MessageBox(NULL, _T("Funcation completed"), _T("Test"), MB_OK);
  21.         return 0;
  22. }
复制代码
编译上面的代码。运行生成的EXE,会依次弹出下面的对话框。

可以看出,在异常处理代码被调用执行后(except块中的代码),程序继续可以继续运行,并正常退出,并没有崩溃!通过使用__try/__except可以捕捉到任何类型的异常,并保证程序不会崩溃!(想想这是多么的神奇,一个程序永远不会崩溃!)
下面解释一下except中表达式各个值的含义:
EXCEPTION_CONTINUE_SEARCH 异常没有被处理,继续向上抛出。如果更上层的代码没有异常捕捉机制,程序就会崩溃。
EXCEPTION_CONTINUE_EXECUTION 异常已经被处理,返回异常发生的地方继续执行。
EXCEPTION_EXECUTE_HANDLER 异常已经被处理,程序继续往后执行。
通过上面的例子可以知道,SEH的异常处理跟C++的异常处理不同,C++的try/catch不能控制异常进程,对于异常,要么处理,要么继续向上抛出。而SEH却能完全控制异常进程,处理完异常之后,还能决定进该进程如何执行。只要SEH运用得当,编写一个永不崩溃的应用程序成为可能。但是SEH有一个致命的弱点,那就是它是一种结构化的异常处理,所以不支持面向对象。下面用具体的VC++控制台程序来说明。// 一个有函数调用的类
  1. // class CrashTest { public: CrashTest() {} ~CrashTest() {} void Test() { Crash(); } private: void Crash() { // 除零,人为的使程序崩溃 // int i = 13; int j = 0; int m = i / j; } }; int _tmain(int argc, _TCHAR* argv[]) { __try { CrashTest test; test.Test(); } __except(EXCEPTION_EXECUTE_HANDLER) { // 在这里添加处理程序崩溃情况的代码 // } return 0; }
复制代码
上面的代码不能通过编译,VC++编译器会给出这样的错误信息:error C2712: Cannot use __try in functions that require object unwinding。错误原因很简单,try块内使用了对象。
要想解决这个问题,可以把使用对象的逻辑放到一个函数里,然后在try里调用这个函数,来骗过编译器。把上面的代码修改成下面这样就可以通过编译。void Test(){        CrashTest test;        test.Test();}int _tmain(int argc, _TCHAR* argv[]){        __try        {                Test();        }        __except(EXCEPTION_EXECUTE_HANDLER)        {                // 在这里添加处理程序崩溃情况的代码                //        }        return 0;}作者:starlee 发表于2011-7-27 9:45:58 原文链接
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-12-4 01:10 , Processed in 0.020434 second(s), 5 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表