鱼C论坛

 找回密码
 立即注册
查看: 2623|回复: 5

[技术交流] 未处理异常 2. 异常处理程序

[复制链接]
发表于 2016-7-4 11:19:58 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 无符号整形 于 2016-7-4 21:41 编辑

上次说好了要交大家如何私底下处理异常,今天就教。在这篇文章结束时,我会和大家一起讨论如何改编错误的strcat程序。
今天主要讲:
1.__except标识符
2.EXCEPTION_EXECUTE_HANDLER
3.EXCEPTION_CONTINUE_EXECUTION
4.EXCEPTION_CONTINUE_SEARCH
5.升级版的strcat程序

好的,让我们进入正题吧!
1.__except标识符:
__except是一种标识符,当__try块在执行时抛出了异常(注意:它不会像finally块那样不让你退出)就会被执行,它比finally块稍微复杂一点点。因为windows要求__except块必须返回一个值,而且具体返回几是有要求的。
标识符格式:
__try
{
        //你认为很容易出错的代码
}
__except(/*处理的返回值,也可以理解成我们要求操作系统处理的方式*/)
{
        //异常处理程序
}
注意__except关键字,任何时候创建一个__try块,后面必须跟着一个__finally块或者__except块。但是try块后面不能同时有__finally块和__except块也不能有多个__finally块或__except块。但是他们互相可以嵌套
至于后面得参数就留到后面去解释啦!
2.EXCEPTION_EXECUTE_HANDLER
这个标识符用来决定except的处理方式
EXCEPTION_EXECUTE_HANDLER就等于告诉操作系统:“我知道这个错误(错误),并预计这个异常在某种情况下会发生,同时已经写了一些代码去来处理它,让这些代码现在就执行吧!“注意:这个是__except块后面跟的那个括号了面的值,在excpt.h中被定义为1。
EXCEPTION_EXECUTE_HANDLER的使用方法:
__try
{
        //你认为很容易出错的__代码
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
        //异常处理程序
}
好了,让我们试着改编上次的strcat程序吧!
上次的代码:
#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<windows.h>
int main()
{
        __try{
                strcat(NULL, NULL);
        }
        __finally{
                MessageBox(NULL, "发生了未处理异常!", "错误", MB_OK | MB_ICONERROR);
        }
        return 0;
}
这次我们直接把__finally换成__except(EXCEPTION_EXECUTE_HANDLER),表示系统发现错误后立即执行__except'
也就是这样
#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<windows.h>
int main()
{
        __try{
                strcat(NULL, NULL);
        }
        __except (EXCEPTION_EXECUTE_HANDLER){
                MessageBox(NULL, "发生了未处理异常!", "错误", MB_OK | MB_ICONERROR);
        }
        return 0;
}
编译并运行,这下子不会弹出“xxx.exe已停止工作“的对话框了。嘿嘿,倒是弹出下面的对话框
efr.JPG
耶!我们终于可以利用SEH私底下处理错误了!太好了!
这就说明了EXCEPTION_EXECUTE_HANDLER的含义,大家看完之后记得敲代码试试哦!
3.EXCEPTION_CONTINUE_EXECUTION
这个嘛,就是让系统吧出错的语句再执行一次,一般都会导致再次发生错误,然后再次执行而死循环!
不过在某些地方,还是有用的。
下面的代码摘自《Windows核心编程》:
TCHAR g_szBuffer[100];

void FunclinRoosevelt1() {
        int x = 0;
        TCHAR *pchBuffer = NULL;
        
        __try {
                *pchBuffer = TEXT('J');
                X = 5 / X;
        }

        __except(OilFilter1(&pchBuffer) ) {
                MessageBox(NULL, TEXT("An exception occurred") , NULL , MB_OK);
        }
        MessageBox(NULL,        TEXT("Function"), NULL, MB_OK);
}
LONG OilFilrer1(TCHAR **ppchBuffer)  {
        if(*ppchBuffer == NULL){
                *ppchBuffer = g_szBuffer;
                return (EXCEPTION_CONTIUE_EXECUTION);
        }
        return(EXCEPTION_EXECUTE_HANDLER);
}
《Windows核心编程》的解释如下
当函数将字符'J'至置于pchBuffer所指向的内存缓冲区内是,遇到了第一个问题:很不辛,我们没有初始化pchBuffer,让他指向全局内存缓冲区g_szBuffer。因此,pchBuffer的值为NULL.。CPU会抛出一个异常,并对发生异常的__try块所对应的__except块的异常过滤程序进行求值。后者则以变量pchBuffer作为参数值调用OilFilter1。

当OilFilter1开始执行,它首先检查**ppchBuffer的值是是不是NULL,如果是,设置**ppBuffer的值,让他指向全局内存缓冲g_szBuffer。预算这次异常处理返回结果为EXCEPTION_CONTIUE_EXECUTION。系统·在看到过滤程序的返回职为EXCEPTION_CONTIUE_EXECUTION后,将程序控制控制流跳转到导致异常的那条指令,并尝试再次执行这条指令。这次,指令执行成功,'J'被置于g_szBuffer所指向缓冲区的第一个字节。
代码继续执行,将会遇到0作为除数的异常。系统再一次计算异常过滤程序表达式。这一次,OilFilter检查到**ppchBuffer的值不是NULL,于是返回EXCEPTION_EXECUTE_HANDLER,让系统执行except代码块。于是一个消息框被弹出,指明一个错误发生。

4.EXCPTION_CONTIUE_SEARCH
这个就是让系统执行上次的__try块,一般很少用,了解即可。
实例:
#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<windows.h>
int main()
{
        __try{
                strcat(NULL, NULL);
        }
        __except (EXCEPTION_CONTINUE_SEARCH){
                MessageBox(NULL, "发生了未处理异常!", "错误", MB_OK | MB_ICONERROR);
        }
        MessageBox(NULL, "我还好呢!", "提醒", MB_OK | MB_ICONEXCLAMATION);
        return 0;
}
你猜会如何?就是延迟一会就停止工作
wer.JPG





5.升级版strcat程序
我直接上代码看看大家看不看得懂
#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<windows.h>
int main()
{
        __try{
                strcat(NULL, NULL);
        }
        __except (EXCEPTION_EXECUTE_HANDLER){
                MessageBox(NULL, "拼接异常!", "错误", MB_OK | MB_ICONERROR);
        }
        MessageBox(NULL, "我还好呢!", "提醒", MB_OK | MB_ICONEXCLAMATION);
        MessageBox(NULL, "拼接结果:NULLNULL", "结果出来了!", MB_OK | MB_ICONINFORMATION);
        return 0;
}
运行结果:
y1.JPG
y2.JPG

y3.JPG

其他的就要你自己总结了哟!

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-8-4 07:43:59 | 显示全部楼层
__try __except无法在裸函数中使用= =如果我要在裸函数中设置异常处理怎么办?(SEH)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-8-4 08:14:07 From FishC Mobile | 显示全部楼层
黑龍 发表于 2016-8-4 07:43
__try __except无法在裸函数中使用= =如果我要在裸函数中设置异常处理怎么办?(SEH)

不太明白你的意思
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-8-4 09:50:26 | 显示全部楼层

就是说
__try和__except都不能在有__declspec(naked)的函数中,否则不能通过编译,就是说无法通过__try和__except实现异常处理。如果我要在有__declspec(naked)的函数下实现异常处理,该怎么办?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-8-4 13:39:17 From FishC Mobile | 显示全部楼层
黑龍 发表于 2016-8-4 09:50
就是说
__try和__except都不能在有__declspec(naked)的函数中,否则不能通过编译,就是说无法通过__try ...

先写个异常处理函数,然后再用call指令去调用它。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-8-4 15:08:00 | 显示全部楼层
无符号整形 发表于 2016-8-4 13:39
先写个异常处理函数,然后再用call指令去调用它。

        push offset @_@
        push fs:[0]
        mov fs:[0],esp
        mov eax,dr0;产生异常
        call FOd
@_@:
        pop fs:[0]
        add esp,4
这样方便= =
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-22 06:47

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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