看流星社区

 找回密码
 注册账号
查看: 2103|回复: 0

VC++ 异常处理 __try __except的用法

[复制链接]

该用户从未签到

发表于 2020-3-22 19:12:18 | 显示全部楼层 |阅读模式

__try __except的用法:

__try __except是windows 系统独有的异常处理模型,称为SEH( structured exception handling ),SEH的异常处理模型主要由__try __except语句来完成,与标准的try catch相似。

与C++异常处理模型使用catch关键字来定义异常处理模块,而SEH是采用__except关键字来定义;并且catch关键字后面往往接受一个函数参数,可以是各种类型的异常数据对象;

而 __except关键字则不同,它后面跟的却是一个表达式。

例子:
  1. long WINAPI FilterFunc(DWORD dwExceptionCode)
  2. {
  3.    return (dwExceptionCode ==
  4.    STATUS_STACK_OVERFLOW) ?
  5.    EXCEPTION_EXECUTE_HANDLER :
  6.   EXCEPTION_CONTINUE_SEARCH;
  7. }

  8. UINT WINAPI ThreadFunc(LPVOID param)
  9. {
  10.   __try
  11.  {
  12.        // guarded code
  13.  }
  14.  __except (FilterFunc(GetExceptionCode()))
  15.  {
  16.    // 如果是栈溢出,进行处理。
  17.   }
  18. return 0;
  19. }
复制代码



except参数的值有以下三种:

EXCEPTION_CONTINUE_EXECUTION (–1):          异常被忽略,控制流将在异常出现的点之后,继续恢复运行。
EXCEPTION_CONTINUE_SEARCH (0):                 异常不被识别,也即当前的这个__except模块不是这个异常错误所对应的正确的异常处理模块。
                                                                        系统将继续到上 __try __except域中继续查找一个恰当的__except模块。
EXCEPTION_EXECUTE_HANDLER (1):                异常已经被识别,控制流将进入到__except模块中运行异常处理代码



__try __except的关键是如何在 __except模块中获得异常错误的相关信息?

Windows提供了两个API函数来获取异常信息:
  1. LPEXCEPTION_POINTERS GetExceptionInformation(VOID); //取得异常相关信息
  2. DWORD GetExceptionCode(VOID); // 取得异常编号
复制代码



EXCEPTION_POINTERS结构如下,
  1. typedef struct _EXCEPTION_POINTERS
  2. { // exp
  3. PEXCEPTION_RECORD ExceptionRecord;

  4. PCONTEXT ContextRecord;

  5. } EXCEPTION_POINTERS;
复制代码


EXCEPTION_RECORD类型,它记录了一些与异常相关的信息;

CONTEXT数据结构体中记录了异常发生时,线程当时的上下文环境,主要包括寄存器的值。

有了这些信息,__except模块便可以对异常错误进行很好的分类和恢复处理,通常我们需要一个过滤函数来辅助。一般称为是filterfunction.过滤函数只过滤需要处理的异常。

  1. int exception_access_violation_filter(LPEXCEPTION_POINTERS p_exinfo)
  2. {
  3.     if(p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
  4.     {
  5.         messagebox("access vialation exceptionn");

  6.        return EXCEPTION_EXECUTE_HANDLER ; //告诉except处理这个异常
  7.     }
  8.     else
  9.     {
  10.      return EXCEPTION_CONTINUE_SEARCH; //不告诉except处理这个异常
  11.     }
  12. }

  13. int exception_int_divide_by_zero_filter(LPEXCEPTION_POINTERS p_exinfo)
  14. {
  15.     if(p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
  16.     {
  17.         return  EXCEPTION_EXECUTE_HANDLER; //告诉except处理这个异常
  18.     }
  19.    else
  20.    {
  21.     return EXCEPTION_CONTINUE_SEARCH; //不告诉except处理这个异常
  22.    }
  23. }
复制代码



于是,可以这样写这段异常处理代码:
  1. __try
  2. {

  3.   // guarded code

  4. }

  5. __except(exception_access_violation_filter(GetExceptionInformation()))
  6. {

  7. //在此可以调用BugReport程序

  8. }
复制代码




SEH异常处理模型中,也可以抛出一个异常。对应的WindowsAPI函数是RaiseException,
  1. VOID RaiseException(
  2. DWORD dwExceptionCode, // 异常的编号
  3. DWORD dwExceptionFlags, // 异常标记
  4. DWORD nNumberOfArguments, // 参数个数
  5. CONST DWORD *lpArguments //  参数数组首地址
  6. );
复制代码




通常,后三个参数基本不用 SEH异常处理还有__try __finally.类似于java里的try-catch-finally.但是SEH的try只能和except和finally两者之间的一个搭配,不能有try-except-finnaly.

C++异常模型用try-catch语法定义,而SEH异常模型则用try-except语法,与C++异常模型相似,try-except也支持多层的try-except嵌套。

try-except模型中,一个try块只能是有一个except块;而C++异常模型中,一个try块可以有多个catch块。

C++异常模型是按照异常对象的类型来进行匹配查找的;而try-except模型则不同,它通过一个表达式的值来进行判断. __except关键字后面跟的表达式,它可以是各种类型的表达式,

例如,它可以是一个函数调用,或是一个条件表达式,或是一个逗号表达式,或干脆就是一个整 型常量等等。

最常用的是一个函数表达式,并且通过利用GetExceptionCode()或GetExceptionInformation ()函数来获取当前的异常错误信息,便于程序员有效控制异常 错误的分类处理。

SEH异常处理模型中,异常通过RaiseException()函数抛出。RaiseException()函数的作用类似于C++异常模型中的throw。
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-23 14:09

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

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