Analysis of Windows structured exception handling

Source: Internet
Author: User
Tags finally block semaphore windows visual

Recently has been plagued by a problem, is written out of the process is always the cause of the collapse, some places themselves know there may be problems, but in some places there is no way to know what the problem. The more bitter thing is that our program is to need 7x24 service customers, although do not need real-time accurate 0 error, but always can not be broken lost data status. So just by dealing with the problem, we found some solutions, how to capture access to an illegal memory address or 0 divided by a number . Thus encountered this structured exception handling , this is a simple introduction to understand, easy to meet the relevant problems, the first to know the cause of the problem, and then how to solve. Needless to say, let's get down to the chase.


What is structured exception handling

Structured exception handling (structured exception handling, hereinafter referred to as "SEH"), is introduced into the operating system as a system mechanism, and is not itself language-independent. The use of SEH in our own programs allows us to focus on developing key functions, while unifying the exceptions that might occur in the program, making the program more concise and more readable.

Using SHEdoes not mean that you can completely ignore the errors that may occur in your code, but we can separate the software workflow from the exception handling of the software, focus on the important and urgent work, and then deal with this important non-urgent problem that may encounter various errors (not urgent, But absolutely important)

When you use SEH in your program, it becomes compiler-dependent. The burden is mainly borne by the compiler, for example, the compiler produces tables (table) to support SEH data structures, and also provides callback functions.

Note:
Do not confuse she and C + + exception handling. C + + exception handling in the form of the use of keyword catch and throw, this she is not the same form, and then in Windows Visual C + +, through the compiler and the operating system she is implemented.

Of all the mechanisms provided by the Win32 operating system, the most widely used mechanism of openness is probably the number of SHE . The mention of SHEmay be reminiscent of words like *__try,__finally* and *__except*. SHE actually contains two functions: terminating processing (termination handing) and exception handling (exception handing)


Terminating processing

The termination handler ensures that no matter how a block of code (protected code) exits, another block of code (the terminating handler) can always be invoked and executed with the following syntax:

__try{    //Guarded body    //...}__finally{    //Terimnation handler    //...}

The **__try and __finally** keywords mark the two parts of the termination handler. The collaboration between the operating system and the compiler ensures that the termination of the program, regardless of how the protected Code section exits (whether it is a normal exit or an abnormal exit), is invoked, that is, the **__finally** code block can execute.


Normal exit and abnormal exit of try Block

A try block may exit spontaneously due to a return,Goto, exception, or a spontaneous exit due to a successful execution. However, regardless of how the try block exits, the contents of the finally block are executed.

int Func1(){    cout << __FUNCTION__ << endl;    int nTemp = 0;    __try{        //正常执行        nTemp = 22;        cout << "nTemp = " << nTemp << endl;    }    __finally{        //结束处理        cout << "finally nTemp = " << nTemp << endl;    }    return nTemp;}int Func2(){    cout << __FUNCTION__ << endl;    int nTemp = 0;    __try{        //非正常执行        return 0;        nTemp = 22;        cout << "nTemp = " << nTemp << endl;    }    __finally{        //结束处理        cout << "finally nTemp = " << nTemp << endl;    }    return nTemp;}

The results are as follows:

Func1nTemp = 22  //正常执行赋值finally nTemp = 22  //结束处理块执行Func2finally nTemp = 0   //结束处理块执行

The above example shows that by using a termination handler you can prevent premature execution of the return statement, and when the return statement view exits the try block, the compiler will let the finally Code blocks are then executed before it. When the variable is accessed through the semaphore in multithreaded programming, the exception occurs and the signal volume is smooth, so that the thread does not always occupy a semaphore. When the finally code block finishes executing, the function returns.

In order for the entire mechanism to run, the compiler must generate some extra code, and the system must do some extra work, so you should avoid using the return statement in the try code block when writing the code, because it has an impact on the performance of the application, and for the simple demo problem, For programs that run continuously for long periods of time, it's a good thing to take a look at the keyword **__leave** keyword, which can help us find code that has local expansion overhead.

a good rule of thumb: do not terminate the handler with statements that let the try block exit prematurely, which means removing the return,continue,break from the try block and finally block , Goto Statements, put these statements outside the termination handler. The advantage of this is that you do not have to capture which try blocks are exited prematurely, so that the compiler generates the least amount of code, improving the efficiency of the program and the readability of the code.


# # #finally块的清理功能及对程序结构的影响

In the process of coding need to join the need to detect, the detection function is successful execution, if successful to perform this, unsuccessful, need to do some additional cleanup work, such as free memory, close handle and so on. If the detection is not a lot, but it has no effect, but if many tests, and the logic in the software is more complex, it often requires a lot of effort to achieve cumbersome detection judgment. The result will make the program look more complex, greatly reduce the readability of the program, and the volume of the program is increasing.

I have a deep understanding of this problem, in the past in writing through COM calls to the VBA of Word , need to layer to get objects, determine whether the object is successful, perform related operations, and then release the object, a process down, originally one or two rows of VBA Code, C + + written out to be good dozens of lines (this depends on how many objects to operate).

Here's a way to see why some people like scripting languages and don't like C + +.

In order to be more logical and operate Officemore hierarchically,Microsoft divides the application (application) into the following tree structure in logical functions

Application(WORD 为例,只列出一部分)  Documents(所有的文档)        Document(一个文档)            ......  Templates(所有模板)        Template(一个模板)            ......  Windows(所有窗口)        Window        Selection        View        .....  Selection(编辑对象)        Font        Style        Range        ......  ......

Only by understanding the logical hierarchy can we properly manipulate Office. For example, if one of the VBA statements is given:

Application.ActiveDocument.SaveAs "c:\abc.doc"

So, we know that the process of doing this is:

    1. First step, get application
    2. Step two, get ActiveDocument from application .
    3. The third step, calling the document 's function, SaveAs, is a string-type file name.

This is just one of the simplest VBA code. To a slightly more complicated point, at the selected place, insert a bookmark:

 ActiveDocument.Bookmarks.Add Range:=Selection.Range, Name:="iceman"

The process here is as follows:

    1. Get Application
    2. Get ActiveDocument
    3. Get Selection
    4. Get Range
    5. Get Bookmarks
    6. Call Method Add

Every object needs to be judged, error handling, object release, and so on. Here is the pseudo-code bar, all written out a bit long

#define RELEASE_OBJ (obj) if (obj! = NULL) obj->realse ();    BOOL Insertbookmarinword (const string& bookname) {BOOL ret = FALSE;    idispatch* pdispapplication = NULL;    idispatch* pdispdocument = NULL;    idispatch* pdispselection = NULL;    idispatch* pdisprange = NULL;    idispatch* pdispbookmarks = NULL;    HRESULT hr = S_FALSE;    hr = Getapplcaiton (..., &pdispapplication); if (! ( SUCCEEDED (hr) | |    Pdispapplication = = NULL)) return FALSE;    hr = GetActiveDocument (..., &pdispdocument); if (! ( SUCCEEDED (hr) | |        Pdispdocument = = NULL)) {release_obj (pdispapplication);    return FALSE;    } hr = GetActiveDocument (..., &pdispdocument); if (! ( SUCCEEDED (hr) | |        Pdispdocument = = NULL)) {release_obj (pdispapplication);    return FALSE;    } hr = GetSelection (..., &pdispselection); if (! ( SUCCEEDED (hr) | |        Pdispselection = = NULL)) {release_obj (pdispapplication);     Release_obj (pdispdocument);   return FALSE;    } hr = GetRange (..., &pdisprange); if (! ( SUCCEEDED (hr) | |        Pdisprange = = NULL)) {release_obj (pdispapplication);        Release_obj (pdispdocument);        Release_obj (pdispselection);    return FALSE;    } hr = Getbookmarks (..., &pdispbookmarks); if (! ( SUCCEEDED (hr) | |        Pdispbookmarks = = NULL)) {release_obj (pdispapplication);        Release_obj (pdispdocument);        Release_obj (pdispselection);        Release_obj (Pdisprange);    return FALSE;    } hr = Addbookmark (....., bookname); if (!        SUCCEEDED (HR)) {release_obj (pdispapplication);        Release_obj (pdispdocument);        Release_obj (pdispselection);        Release_obj (Pdisprange);        Release_obj (Pdispbookmarks);    return FALSE;    } ret = TRUE; return ret;

This is only pseudo-code, although you can also use the goto to reduce the line of code, but Goto is not good to go wrong, the following program is a bit inattentive goto to not get the place.

BOOL InsertBookmarInWord2 (const string& bookname) {BOOL ret = FALSE;    idispatch* pdispapplication = NULL;    idispatch* pdispdocument = NULL;    idispatch* pdispselection = NULL;    idispatch* pdisprange = NULL;    idispatch* pdispbookmarks = NULL;    HRESULT hr = S_FALSE;    hr = Getapplcaiton (..., &pdispapplication); if (! ( SUCCEEDED (hr) | |    Pdispapplication = = NULL)) goto EXIT6;    hr = GetActiveDocument (..., &pdispdocument); if (! ( SUCCEEDED (hr) | |    Pdispdocument = = NULL)) {goto exit5;    } hr = GetActiveDocument (..., &pdispdocument); if (! ( SUCCEEDED (hr) | |    Pdispdocument = = NULL)) {goto EXIT4;    } hr = GetSelection (..., &pdispselection); if (! ( SUCCEEDED (hr) | |    Pdispselection = = NULL)) {goto EXIT4;    } hr = GetRange (..., &pdisprange); if (! ( SUCCEEDED (hr) | |    Pdisprange = = NULL)) {goto exit3;    } hr = Getbookmarks (..., &pdispbookmarks); if (! ( SUCCEEDED (hr) | |     Pdispbookmarks = = NULL)) {   Got Exit2;    } hr = Addbookmark (....., bookname); if (!    SUCCEEDED (HR)) {goto exit1; } ret = True;exit1:release_obj (pdispapplication); Exit2:release_obj (pdispdocument); Exit3:release_obj (pDispSe lection); Exit4:release_obj (Pdisprange); Exit5:release_obj (Pdispbookmarks); exit6:return ret;

The

here or through the terminating handler of SEH to re-use this method is not clearer.

BOOL InsertBookmarInWord3 (const string& bookname) {BOOL ret = FALSE;    idispatch* pdispapplication = NULL;    idispatch* pdispdocument = NULL;    idispatch* pdispselection = NULL;    idispatch* pdisprange = NULL;    idispatch* pdispbookmarks = NULL;    HRESULT hr = S_FALSE;        __try{hr = Getapplcaiton (..., &pdispapplication); if (! ( SUCCEEDED (hr) | |        Pdispapplication = = NULL)) return FALSE;        hr = GetActiveDocument (..., &pdispdocument); if (! ( SUCCEEDED (hr) | |        Pdispdocument = = NULL)) {return FALSE;        } hr = GetActiveDocument (..., &pdispdocument); if (! ( SUCCEEDED (hr) | |        Pdispdocument = = NULL)) {return FALSE;        } hr = GetSelection (..., &pdispselection); if (! ( SUCCEEDED (hr) | |        Pdispselection = = NULL)) {return FALSE;        } hr = GetRange (..., &pdisprange); if (! ( SUCCEEDED (hr) | |        Pdisprange = = NULL)) {return FALSE; } hr = Getbookmarks (..., &pdispbookmarks); if (! ( SUCCEEDED (hr) | |        Pdispbookmarks = = NULL)) {return FALSE;        } hr = Addbookmark (....., bookname); if (!        SUCCEEDED (HR)) {return FALSE;    } ret = TRUE;        } __finally{Release_obj (pdispapplication);        Release_obj (pdispdocument);        Release_obj (pdispselection);        Release_obj (Pdisprange);    Release_obj (Pdispbookmarks); } return ret;

The functions of these functions are the same. You can see that the cleanup functions in Insertbookmarinword (release_obj) are everywhere, while the cleanup functions in InsertBookmarInWord3 are all concentrated in the finally block, if you are reading the code just look at the contents of the try block to understand the program flow. The two functions themselves are very small, you can carefully understand the difference between the two functions.


Keyword __leave

Using the **__leave keyword in a try block causes the program to jump to the end of the try block, which naturally enters the finally block.
For the InsertBookmarInWord3in the example above, the return in thetry block can be replaced entirely with
__leave**. The difference between the two is that using return will cause the **__leave** to exit the system locally and increase the overhead, and if you use it, you will naturally exit the try block with much less overhead.

BOOL InsertBookmarInWord4 (const string& bookname) {BOOL ret = FALSE;    idispatch* pdispapplication = NULL;    idispatch* pdispdocument = NULL;    idispatch* pdispselection = NULL;    idispatch* pdisprange = NULL;    idispatch* pdispbookmarks = NULL;    HRESULT hr = S_FALSE;        __try{hr = Getapplcaiton (..., &pdispapplication); if (! ( SUCCEEDED (hr) | |        Pdispapplication = = NULL)) __leave;        hr = GetActiveDocument (..., &pdispdocument); if (! ( SUCCEEDED (hr) | |        Pdispdocument = = NULL)) __leave;        hr = GetActiveDocument (..., &pdispdocument); if (! ( SUCCEEDED (hr) | |        Pdispdocument = = NULL)) __leave;        hr = GetSelection (..., &pdispselection); if (! ( SUCCEEDED (hr) | |        Pdispselection = = NULL)) __leave;        hr = GetRange (..., &pdisprange); if (! ( SUCCEEDED (hr) | |        Pdisprange = = NULL)) __leave;        hr = Getbookmarks (..., &pdispbookmarks); if (! ( SucceedeD (hr) | |        Pdispbookmarks = = NULL)) __leave;        hr = Addbookmark (..., bookname); if (!        SUCCEEDED (HR)) __leave;    ret = TRUE;        } __finally{Release_obj (pdispapplication);        Release_obj (pdispdocument);        Release_obj (pdispselection);        Release_obj (Pdisprange);    Release_obj (Pdispbookmarks); } return ret;}


Exception handlers

Software exceptions are not what we would like to see, but there are often errors, such as CPU capture similar to illegal memory access and in addition to 0 of such problems, once the detection of such errors, throw related exceptions, the operating system will give us an opportunity to view the exception type, and run the program itself to handle the exception. The exception handler structure code is as follows

  __try {      // Guarded body    }    __except ( exception filter ) {      // exception handler    }

Note that the keyword **__except**, any try block, must be followed by a finally code block or a except code block, but the try cannot have both Finally and except blocks, and cannot have multiple finnaly or except blocks at the same time, but can be nested with each other


Exception handling Basic Process
int Func3(){    cout << __FUNCTION__ << endl;    int nTemp = 0;    __try{        nTemp = 22;        cout << "nTemp = " << nTemp << endl;    }    __except (EXCEPTION_EXECUTE_HANDLER){        cout << "except nTemp = " << nTemp << endl;    }    return nTemp;}int Func4(){    cout << __FUNCTION__ << endl;    int nTemp = 0;    __try{        nTemp = 22/nTemp;        cout << "nTemp = " << nTemp << endl;    }    __except (EXCEPTION_EXECUTE_HANDLER){        cout << "except nTemp = " << nTemp << endl;    }    return nTemp;}

The results are as follows:

Func3nTemp = 22  //正常执行Func4except nTemp = 0 //捕获异常,

The try block in Func3 is just a simple operation, so it will not cause an exception, so the code in the except block will not be executed,Func4 in the try block view with 22 in addition to 0, Causes the CPU to capture this event, and throws, the system locates to the except block, handles the exception, there is an exception filter expression, there are three definitions in the system (defined in Windows Excpt.h):

1. EXCEPTION_EXECUTE_HANDLER:    我知道这个异常了,我已经写了代码来处理它,让这些代码执行吧,程序跳转到except块中执行并退出2. EXCEPTION_CONTINUE_SERCH    继续上层搜索处理except代码块,并调用对应的异常过滤程序3. EXCEPTION_CONTINUE_EXECUTION    返回到出现异常的地方重新执行那条CPU指令本身

Polygons are two basic ways to use:

    • Method One: Directly using one of the three return values of the filter

      __try {   ……}__except ( EXCEPTION_EXECUTE_HANDLER ) {   ……}
    • Mode Two: Custom filters
      ```
      __try {
      ......
      }
      __except (Myfilter (GetExceptionCode ()))
      {
      ......
      }

LONG myfilter (DWORD dwexceptioncode)
{
if (Dwexceptioncode = = exception_access_violation)
return exception_execute_handler;
Else
return exception_continue_search;
}

<br>##.NET4.0中捕获SEH异常在.NET 4.0之后,CLR将会区别出一些异常(都是SEH异常),将这些异常标识为破坏性异常(Corrupted State Exception)。针对这些异常,CLR的catch块不会捕捉这些异常,一下代码也没有办法捕捉到这些异常。

try{
//....
}
catch (Exception ex)
{
Console.WriteLine (ex. ToString ());
}

因为并不是所有人都需要捕获这个异常,如果你的程序是在4.0下面编译并运行,而你又想在.NET程序里捕捉到SEH异常的话,有两个方案可以尝试: - 在托管程序的.config文件里,启用legacyCorruptedStateExceptionsPolicy这个属性,即简化的.config文件类似下面的文件:

App.

这个设置告诉CLR 4.0,整个.NET程序都要使用老的异常捕捉机制。-  在需要捕捉破坏性异常的函数外面加一个HandleProcessCorruptedStateExceptions属性,这个属性只控制一个函数,对托管程序的其他函数没有影响,例如:

[Handleprocesscorruptedstateexceptions]
try{
//....
}
catch (Exception ex)
{
Console.WriteLine (ex. ToString ());
}
```

Analysis of Windows structured exception handling

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.