zoukankan      html  css  js  c++  java
  • [转]让程序在崩溃时体面的退出之SEH

    原文地址:http://blog.csdn.net/starlee/article/details/6636723

            SEH的全称是Structured Exception Handling,是Windows操作系统提供的一种异常处理方式。SEH是属于操作系统的特性,不为特定语言设计,从它的名字就能看出它是一种结构化的异常处理方式。SEH包括了2个部分:终止处理__try/__finally和异常处理__try/__except,下面分别进行介绍。

            终止处理__try/__finally
            __try/__finally可以保证无论try块内的代码执行结果如何,finally块内的代码总会被调用和执行。现在用下面的这个VC++中的控制台程序来说明。

    [cpp] view plaincopy
     
    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.         //  
    9.         int i = 13;  
    10.         int j = 0;  
    11.         int m = i / j;  
    12.     }  
    13.     __finally  
    14.     {  
    15.         // 在这里添加处理程序崩溃情况的代码  
    16.         //  
    17.   
    18.         // 这里以弹出一个对话框为例子  
    19.         //  
    20.         MessageBox(NULL, _T("Message from '__finally' section"), _T("Test"), MB_OK);  
    21.     }  
    22.   
    23.     MessageBox(NULL, _T("Funcation completed"), _T("Test"), MB_OK);  
    24.   
    25.     return 0;  
    26. }  

            编译上面的代码。运行生成的EXE,会弹出下面的对话框。

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

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

            点击OK按钮后,程序正常退出。
            由上面的例子可以看出,无论try块中的代码会不会出现异常,在程序终止的时候,finally块中的代码都会被调用和执行。所以一般情况下,finally块中的代码都是用来做一些清理工作和资源的释放。

            异常处理__try/__except
            __try/__except是用来捕捉异常的,只有当try块中的代码出现异常的时候,except块中的代码才会被调用和执行。它的语法是这样的:

    [cpp] view plaincopy
     
    1. __try  
    2. {  
    3.     // guarded code  
    4. }  
    5. __except(expression)  
    6. {  
    7.      // exception handler code  
    8. }  

            它最大的一个好处就是可以完全控制异常进程。expression的值决定了异常被处理完后,进程该如何执行。下面依然用VC++中的控制台程序来说明。

    [cpp] view plaincopy
     
    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.         //  
    9.         int i = 13;  
    10.         int j = 0;  
    11.         int m = i / j;  
    12.     }  
    13.     __except(EXCEPTION_EXECUTE_HANDLER)  
    14.     {  
    15.         // 在这里添加处理程序崩溃情况的代码  
    16.         //  
    17.   
    18.         // 这里以弹出一个对话框为例子  
    19.         //  
    20.         MessageBox(NULL, _T("Message from '__except' section"), _T("Test"), MB_OK);  
    21.     }  
    22.   
    23.     MessageBox(NULL, _T("Funcation completed"), _T("Test"), MB_OK);  
    24.   
    25.     return 0;  
    26. }  

            编译上面的代码。运行生成的EXE,会依次弹出下面的对话框。

            可以看出,在异常处理代码被调用执行后(except块中的代码),程序继续可以继续运行,并正常退出,并没有崩溃!通过使用__try/__except可以捕捉到任何类型的异常,并保证程序不会崩溃!(想想这是多么的神奇,一个程序永远不会崩溃!)
            下面解释一下except中表达式各个值的含义:

    EXCEPTION_CONTINUE_SEARCH        异常没有被处理,继续向上抛出。如果更上层的代码没有异常捕捉机制,程序就会崩溃。
    EXCEPTION_CONTINUE_EXECUTION   异常已经被处理,返回异常发生的地方继续执行。
    EXCEPTION_EXECUTE_HANDLER        异常已经被处理,程序继续往后执行。

            通过上面的例子可以知道,SEH的异常处理跟C++的异常处理不同,C++的try/catch不能控制异常进程,对于异常,要么处理,要么继续向上抛出。而SEH却能完全控制异常进程,处理完异常之后,还能决定进该进程如何执行。只要SEH运用得当,编写一个永不崩溃的应用程序成为可能。但是SEH有一个致命的弱点,那就是它是一种结构化的异常处理,所以不支持面向对象。下面用具体的VC++控制台程序来说明。

    [cpp] view plaincopy
     
    1. // 一个有函数调用的类  
    2. //   
    3. class CrashTest  
    4. {  
    5. public:  
    6.     CrashTest() {}  
    7.     ~CrashTest() {}  
    8.   
    9.     void Test()   
    10.     {   
    11.         Crash();   
    12.     }  
    13.   
    14. private:  
    15.     void Crash()   
    16.     {   
    17.         // 除零,人为的使程序崩溃  
    18.         //  
    19.         int i = 13;  
    20.         int j = 0;  
    21.         int m = i / j;  
    22.     }  
    23. };  
    24.   
    25. int _tmain(int argc, _TCHAR* argv[])  
    26. {  
    27.     __try  
    28.     {  
    29.         CrashTest test;  
    30.         test.Test();  
    31.     }  
    32.     __except(EXCEPTION_EXECUTE_HANDLER)  
    33.     {  
    34.         // 在这里添加处理程序崩溃情况的代码  
    35.         //  
    36.     }  
    37.   
    38.     return 0;  
    39. }  

            上面的代码不能通过编译,VC++编译器会给出这样的错误信息:error C2712: Cannot use __try in functions that require object unwinding。错误原因很简单,try块内使用了对象。
            要想解决这个问题,可以把使用对象的逻辑放到一个函数里,然后在try里调用这个函数,来骗过编译器。把上面的代码修改成下面这样就可以通过编译。

    [cpp] view plaincopy
     
      1. void Test()  
      2. {  
      3.     CrashTest test;  
      4.     test.Test();  
      5. }  
      6.   
      7. int _tmain(int argc, _TCHAR* argv[])  
      8. {  
      9.     __try  
      10.     {  
      11.         Test();  
      12.     }  
      13.     __except(EXCEPTION_EXECUTE_HANDLER)  
      14.     {  
      15.         // 在这里添加处理程序崩溃情况的代码  
      16.         //  
      17.     }  
      18.   
      19.     return 0;  
      20. }  
  • 相关阅读:
    cf854B Maxim Buys an Apartment
    Snuke's Coloring 2-1
    P1087 FBI树
    Card Game for Three
    Many Formulas
    排队
    苹果消消乐(尺取法)
    猴子选大王(约瑟夫)
    进制转化
    UIProgress控件的属性和方法
  • 原文地址:https://www.cnblogs.com/gomen/p/3508491.html
Copyright © 2011-2022 走看看