让程序在崩溃时体面的退出之SEH
SEH的全称是Structured Exception Handling,是Windows操作系统提供的一种异常处理方式。SEH是属于操作系统的特性,不为特定语言设计,从它的名字就能看出它是一种结构化的异常处理方式。SEH包括了2个部分:终止处理__try/__finally和异常处理__try/__except,下面分别进行介绍。
终止处理__try/__finally
__try/__finally可以保证无论try块内的代码执行结果如何,finally块内的代码总会被调用和执行。现在用下面的这个VC++中的控制台程序来说明。
- int _tmain(int argc, _TCHAR* argv[])
- {
- __try
- {
- MessageBox(NULL, _T("Message from '__try' section"), _T("Test"), MB_OK);
- // 除零,人为的使程序崩溃
- //
- int i = 13;
- int j = 0;
- int m = i / j;
- }
- __finally
- {
- // 在这里添加处理程序崩溃情况的代码
- //
- // 这里以弹出一个对话框为例子
- //
- MessageBox(NULL, _T("Message from '__finally' section"), _T("Test"), MB_OK);
- }
- MessageBox(NULL, _T("Funcation completed"), _T("Test"), MB_OK);
- return 0;
- }
编译上面的代码。运行生成的EXE,会弹出下面的对话框。
点击OK按钮后,程序会崩溃。
在出现上面这个对话框的时候点击Cancel,将控制权返还给程序,那么下面的对话框就会弹出。
点击OK按钮后,程序正常退出。
由上面的例子可以看出,无论try块中的代码会不会出现异常,在程序终止的时候,finally块中的代码都会被调用和执行。所以一般情况下,finally块中的代码都是用来做一些清理工作和资源的释放。
异常处理__try/__except
__try/__except是用来捕捉异常的,只有当try块中的代码出现异常的时候,except块中的代码才会被调用和执行。它的语法是这样的:
- __try
- {
- // guarded code
- }
- __except(expression)
- {
- // exception handler code
- }
它最大的一个好处就是可以完全控制异常进程。expression的值决定了异常被处理完后,进程该如何执行。下面依然用VC++中的控制台程序来说明。
- int _tmain(int argc, _TCHAR* argv[])
- {
- __try
- {
- MessageBox(NULL, _T("Message from '__try' section"), _T("Test"), MB_OK);
- // 除零,人为的使程序崩溃
- //
- int i = 13;
- int j = 0;
- int m = i / j;
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- // 在这里添加处理程序崩溃情况的代码
- //
- // 这里以弹出一个对话框为例子
- //
- MessageBox(NULL, _T("Message from '__except' section"), _T("Test"), MB_OK);
- }
- MessageBox(NULL, _T("Funcation completed"), _T("Test"), MB_OK);
- return 0;
- }
编译上面的代码。运行生成的EXE,会依次弹出下面的对话框。
可以看出,在异常处理代码被调用执行后(except块中的代码),程序继续可以继续运行,并正常退出,并没有崩溃!通过使用__try/__except可以捕捉到任何类型的异常,并保证程序不会崩溃!(想想这是多么的神奇,一个程序永远不会崩溃!)
下面解释一下except中表达式各个值的含义:
EXCEPTION_CONTINUE_SEARCH 异常没有被处理,继续向上抛出。如果更上层的代码没有异常捕捉机制,程序就会崩溃。
EXCEPTION_CONTINUE_EXECUTION 异常已经被处理,返回异常发生的地方继续执行。
EXCEPTION_EXECUTE_HANDLER 异常已经被处理,程序继续往后执行。
通过上面的例子可以知道,SEH的异常处理跟C++的异常处理不同,C++的try/catch不能控制异常进程,对于异常,要么处理,要么继续向上抛出。而SEH却能完全控制异常进程,处理完异常之后,还能决定进该进程如何执行。只要SEH运用得当,编写一个永不崩溃的应用程序成为可能。但是SEH有一个致命的弱点,那就是它是一种结构化的异常处理,所以不支持面向对象。下面用具体的VC++控制台程序来说明。
- // 一个有函数调用的类
- //
- 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;
- }
让程序在崩溃时体面的退出之SEH相关推荐
- 让程序在崩溃时体面的退出之总结
终于把<让程序在崩溃时体面的退出>这个系列的6篇文章全部发表出来了. 这6篇文章分别是: < 让程序在崩溃时体面的退出之Unhandled Excep ...
- 让程序在崩溃时体面的退出之Dump文件
在我的那篇< 让程序在崩溃时体面的退出之CallStack>中提供了一个在程序崩溃时得到CallStack的方法.可是要想得到CallStack,必须有pdb文件的支持.但是一般情况下,发 ...
- 让程序在崩溃时体面的退出之Unhandled Exception
程序是由代码编译出来的,而代码是由人写的.人非圣贤,孰能无过.所以由人写的代码有缺陷是很正常的.当然很多异常都在开发阶段被考虑到而添加了处理代码,或者用try/catch对可能出现异常的地方进行额外的 ...
- 编写的windows程序,崩溃时产生crash dump文件的办法
一.引言 dump文件是C++程序发生异常时,保存当时程序运行状态的文件,是调试异常程序重要的方法,所以程序崩溃时,除了日志文件,dump文件便成了我们查找错误的最后一根救命的稻草.windows程序 ...
- windows c++程序在崩溃时自动生成dump
作者:刘树伟 网上找到的windows在进程崩溃时自动抓dump的代码,几乎全部是由进程自己调用实现的,这个其实在一些情况下是有问题的. 原因1:程序已经崩溃,再创建dump,可能失败. 原因2:Mi ...
- 销户c语言,c – 如何在注销时优雅地退出QApplication?
我有一个带有通知区域图标的应用程序,因此主窗口可能会忽略关闭事件.我正在尝试保存应用程序退出的首选项和历史记录.我还想在应用程序运行时处理注销.虽然应用程序是跨平台的,但它在GNU / Linux中最 ...
- 栈windows linux,Linux+Windows: 程序崩溃时,在 C++ 代码中,如何获取函数调用栈信息...
一.前言 程序在执行过程中 crash 是非常严重的问题,一般都应该在测试阶段排除掉这些问题,但是总会有漏网之鱼被带到 release 阶段. 因此,程序的日志系统需要侦测这种情况,在代码崩溃的时候获 ...
- 解决QT接受串口数据时数据更新不及时,串口数据太多导致程序界面崩溃,串口接收数据过快等问题
1.问题背景 最近在使用上位机测试传感器接受数据是否正常,发现了很多问题,由于没有系统的学过Qt,用到什么库就学什么库,导致库中的函数很多不清晰,产生了标题中的一系列问题,经过不断的尝试,终于解决上述 ...
- iOS中Mach异常和signal信号介绍,以及当APP崩溃时做线程保活弹出程序异常提示框
我们经常会遇到APP闪退和崩溃的问题,那么我们应该通过什么变量去监听APP的异常呢?如何在程序崩溃时,保证程序不闪退,并给用户弹出一个提示框呢? 这是本文将要讲述的内容. 先介绍2个概念,Mach异常 ...
最新文章
- OC特有语法:分类category,给NSString增加方法计算字符串中数字的个数
- Android sdk Drow9patch使用
- error C2018: unknown character '0xa1'解决方法
- 这些工具你利用好了吗?
- 关于spring 获取不到网站上的xsd的处理记录
- 【VB.NET】VB.NET窗体方法示例
- python经典教程游戏_使用pygame制作经典小游戏:五子棋
- 下面的 3 条指令执行后, cpu 几次修改 IP? 都是在什么时候? 最后 IP 中的值是多少?
- 第 8 章 TokyoCabinet/Tyrant
- Linux删除带空格的文件 删除最后一个后缀名
- 射频识别(RFID)技术与ETC技术简介
- 分享一些个人的抢票过程
- java全能速查宝典_Java全能速查宝典_IT教程网
- 文本修饰标签(text-decoration)
- 涉及到第三方支付接口该如何测试?
- 太简单了!串口触摸屏开发HMI的全流程介绍成都工控开发
- 浅谈互联网DD攻击和CC攻击
- excel表格下拉选项怎么设置_excel怎么筛选?excel表格中筛选怎么用?
- 碎片化学习Java(十六)Java for得出年份生肖
- Java--Mac系统安装JDK1.8及环境变量配置