SEH(structured exception handling)基础篇---终止处理程序

前序:最近看SEH看的头晕脑胀/(ㄒoㄒ)/~~,SEH最开始是Windows提供的异常处理机制,只是一个简单的框架,而我们现在使用的SEH都是编译器已经在系统提供的最基础的框架上做了修改的增强版(原始版比较原始,牵扯到大量Windows基础知识,并且需要反汇编看汇编代码来理解。。。。本人现在功力较浅,需要慢慢消化,先看一下增强版,通过C和C++来接触一下。

SEH包含两部分功能:终止处理(termination handling)和异常处理(exception handling)。在这先讲一下终止处理程序。

终止程序确保不管一个代码块(被保护代码(the guarded body))是如何推出的,另一个代码块(终止处理程序)总能被调用和执行。

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

在Guarded body中除非调用ExitProcess,ExitThread,TerminateProcess,TerminateThread来终止进程或线程从而__finally代码块不会被调用,其他情况,终止处理程序都会被调用。

下面通过几个伪代码来理解一下DWORD WhiteLearner_SEH_1(){    DWORD dwTemp;

//等待一个信号
    WaitForSingleObject(__hSem, INFINITE);

    __dwProtectedData = 5;
    dwTemp = __dwProtectedData;
    return dwTemp;
    //信号释放
    ReleaseSemaphore(__hSem, 1, NULL);
    return dwTemp;
}
DWORD WhiteLearner_SEH_2() {
    DWORD dwTemp;
    __try {
        //等待一个信号
        WaitForSingleObject(__hSem, INFINITE);

        __dwProtectedData = 5;
        dwTemp = __dwProtectedData;
        return dwTemp;
    }
    __finally {
        //信号释放
        ReleaseSemaphore(__hSem, 1, NULL);
    }   dwTemp = 9;
    return dwTemp;
}

可以看出来,WhiteLearner_SEH_1()中没有用SEH,在ReleaseSemaphore之前便return掉,线程便没有机会释放信号量资源,其他线程当然也不会在得到对这个信号量的控制权。不难想象,在等待同一个信号量的其他线程因此再也没有机会运行,这样的执行顺序带来了很严重的问题。然而在WhiteLearner_SEH_2()中我们运用了__finally,在__try中return之前,__finally会提前运行,__finally代码块中代码运行完成后再次返回到__try代码块中return结束线程。注意,__finally代码块后面的代码没有得到运行便直接return了,返回值为5。

下面更详细具体的解释一下终止处理程序的意义:

DWORD WhiteLearner_SEH_3(){
    DWORD dwTemp;
    //等待信号量
    WaitForSingleObject(__hSem, INFINITE);
    dwTemp = Funcinator(__dwProtectedData);
    //释放信号量
    ReleaseSemaphore(__hSem, 1, NULL);
    return dwTemp;
}

这个函数中释放前进行了一系列操作Funcinator,如果操作中存在缺陷导致程序非法访问内存,则会导致Windows错误报告(Windows Error Reporting,WER)弹出对话框:“Application has stopped working”。如果用户取消对话框,则进程直接终止,也就是说信号量没有来的及释放,跟WhiteLearner_SEH_1函数类似。

还有,__finally代码块是程序顺序运行也会执行的代码,并且只要__try代码块没有正常运行结束,__finally代码块就会插入__try中运行。(忽略栈耗尽异常)__finally代码块运行的第三种情况--全局展开,这个在SEH下一部分异常处理再详细介绍。

DWORD WhiteLearner_SEH_4() {
    DWORD dwTemp = 0;
    while (dwTemp < 10)
    {
        __try {
            if (dwTemp == 2)
                continue;
            if (dwTemp == 3)
                break;
        }
        __finally {
            dwTemp++;
        }
        dwTemp++;
    }
    return dwTemp;
}

这个函数的返回值是4。具体过程希望读者自己思考。

最后,终止处理程序也可以进行最后所有的清理工作:

DWORD WhiteLearner_SEH_5() {
    HANDLE hFile = INVALID_HANDLE_VALUE;
    PVOID  pvBuf = NULL;
    BOOL   bFunctionOk = FALSE;
    __try {
        DWORD dwNumBytesRead;
        BOOL  IsOk;
        hFile = CreateFile(TEXT("SOMEDATA>DAT"), GENERIC_READ, FILE_SHARE_READ, NULL,
            OPEN_EXISTING, 0, NULL);
        if (hFile == INVALID_HANDLE_VALUE){
            //进入__finally
            __leave;
        }

        pvBuf = VirtualAlloc(NULL,  0x1000, MEM_COMMIT, PAGE_READWRITE);
        if (pvBuf == NULL) {
            __leave;
        }
        IsOk = ReadFile(hFile, pvBuf, 0x1000, &dwNumBytesRead, NULL);
        if (!IsOk || dwNumBytesRead == 0) {
            __leave;
        }
        bFunctionOk = TRUE;
    }
    __finally {
        if (pvBuf != NULL) {
            VirtualFree(pvBuf, MEM_RELEASE | MEM_DECOMMIT);
        }
        if (hFile != INVALID_HANDLE_VALUE)
        {
            CloseHandle(hFile);
        }
    }
    return(bFunctionOk);
}

通过这次介绍大家应该能感受到终止处理程序的强大功能,总结一下有下面几条:

1.因为清理工作集中在一个地方执行,并且保证能得到执行,从而简化了错误处理。

2.提高了代码的可读性。

3.让代码更容易维护。

4.如果正常使用,他们对程序性能和体积的影响是微小的。

感谢大家阅读,本人现在也在黑暗中摸索前进,欢迎互相讨论,互相学习。

参考资料:《WINDOWS核心编程》

大神博客http://www.cnblogs.com/lanrenxinxin/p/4631836.html#3340777

时间: 2024-08-09 11:39:34

SEH(structured exception handling)基础篇---终止处理程序的相关文章

[转载]A Crash Course on the Depths of Win32 Structured Exception Handling

转自:[已完工][经典文章翻译]A Crash Course on the Depths of Win32 Structured Exception Handling 原文题目: <<A Crash Course on the Depths of Win32™ Structured Exception Handling>> 原文地址: http://www.microsoft.com/msj/0197/Exception/Exception.aspx 原作者: Matt Pietr

Exception Handling引入MVP

异常处理(Exception Handling)是所有系统的最基本的基础操作之一,其它的比如日志(Logging).审核(Auditing).缓存(Caching).事务处理(Transaction)等: 今天,来把异常处理引入到我们在<MVP之V和P的交互>中Calculator的实例中,简单的实现AOP.实例运行如图: 那么,开始我们开简单的介绍下Enterprise Library EHAB(Exception Handling Application Block)提供了一种基于策略(P

风雨java路之【基础篇】——异常的那些事儿

异常,说白了,就是不正常,就是由于种种原因产生了非正常的结果.生活中此现象比比皆是,举个简单的例子: 去ATM机取钱,插入银行卡,没反应,这就是异常,可能是机器坏了,也可能是卡消磁了等等:读卡成功,输入密码时,铵错按钮,这也是异常:密码正确,想取¥1000,结果余额不足,这又是异常:钱取完了,卡被吞了,这还是异常:-- 拿人来说,沙尘迷眼了,这是异常情况:喝水呛着了,这也是异常:水指不小心划破流血了,这也是异常:-- 出现这些情况该怎么办?那就需要"异常机制",对于ATM机,他有自己的

oracle(sql)基础篇系列(五)&mdash;&mdash;PLSQL、游标、存储过程、触发器

  PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语言是为了补充SQL语言的,是带有了分支和循环的语言. PL/SQL 语法 基本数据类型声明 declare v_name varchar2(20); v_temp number(1); v_count binary_integer := 0; v_sal number(7,2) := 4000.00

Hybrid APP基础篇(四)-&gt;JSBridge的原理

说明 JSBridge实现原理 目录 前言 参考来源 前置技术要求 楔子 原理概述 简介 url scheme介绍 实现流程 实现思路 第一步:设计出一个Native与JS交互的全局桥对象 第二步:JS如何调用Native 第三步:Native如何得知api被调用 第四步:分析url-参数和回调的格式 第五步:Native如何调用JS 第六步:H5中api方法的注册以及格式 进一步完善JSBridge方案 思路 实现 注意 完整的JSBridge 完整调用流程图 另外实现:不采用url sche

Qt入门之基础篇 ( 二 ) :Qt项目建立、编译、运行和发布过程解析

转载请注明出处:CN_Simo. 题解: 本篇内容主讲Qt应用从创建到发布的整个过程,旨在帮助读者能够快速走进Qt的世界. 本来计划是讲解Qt源码静态编译,如此的话读者可能并不能清楚地知道为何要静态编译,所以借此篇内容说明一下原由并为之后文章的学习做准备. 即使本片内容只是在围绕一个小小的HelloWorld程序开展,但还是希望朋友们不要急于求成,"欲速则不达". 文章整体思路: 我们循序渐进地来看,一个Qt应用的完成有以下一个重要的步骤: 项目创建->源码编译->程序运行

shell脚本编程之基础篇(二)

shell脚本编程之基础篇(二) ============================================================================== 概述: ============================================================================== 退出状态 ★进程使用退出状态来报告成功或失败 ◆0 代表成功,1-255代表失败 ◆$? 变量保存最近的命令退出状态 (查看:echo $?)

Python之路【第十六篇】:Django【基础篇】

Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. 基本配置 一.创建django程序 终端命令:django-admin startproject sitename IDE创建Django程序时,本质上都是自动执行上述命令 其他常用命令: python manage.py runserver

java基础篇---I/O技术(三)

接上一篇java基础篇---I/O技术(二) Java对象的序列化和反序列化 什么叫对象的序列化和反序列化 要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream).使用对象输出流输出序列化对象的步骤,有时也成序列化,而使用对象输入流读入对象的过程,有时也称为反序列化 一个对象产生之后实际上是在内存中为其开辟了一个存储空间,方便存储信息. 对象序列化就是把一个对象变成二进制的数据流的一个方法,通过对象序列化可以反驳的