[笔记]Windows核心编程《二十三》结构化异常处理

简介: Windows核心编程《二十三》结构化异常处理

系列文章目录



[笔记]Windows核心编程《一》错误处理、字符编码

[笔记]Windows核心编程《二》内核对象

[笔记]Windows核心编程《三》进程

[笔记]Windows核心编程《四》作业

[笔记]快乐的LInux命令行《五》什么是shell

[笔记]Windows核心编程《五》线程基础

[笔记]Windows核心编程《六》线程调度、优先级和关联性

[笔记]Windows核心编程《七》用户模式下的线程同步

[笔记]Windows核心编程《八》用内核对象进行线程同步

[笔记]Windows核心编程《九》同步设备I/O和异步设备I/O

[笔记]Windows核心编程《十一》Windows线程池

[笔记]Windows核心编程《十二》纤程

[笔记]Windows核心编程《十三》windows内存体系结构

[笔记]Windows核心编程《十四》探索虚拟内存

[笔记]Windows核心编程《十五》在应用程序中使用虚拟内存

[笔记]Windows核心编程《十六》线程栈

[笔记]Windows核心编程《十七》内存映射文件

[笔记]Windows核心编程《十八》堆栈

[笔记]Windows核心编程《十九》DLL基础

[笔记]Windows核心编程《二十》DLL的高级操作技术

[笔记]Windows核心编程《二十一》线程本地存储器TLS

[笔记]Windows核心编程《二十二》注入DLL和拦截API

[笔记]Windows核心编程《二十三》结构化异常处理


文章目录



   系列文章目录

   前言

   C++异常处理的情况

       情况1 释放信标情况

       情况2 释放信标 try中加入return

       情况3 释放信标 在try内使用Goto

       情况4 释放信标 try调用函数抛异常

       情况5 循环中使用try-finally

   总结

       1.SEH(Structured Exception Handling)和SJLJ(SetJump LongJump)区别对比

       SEH:

       2.SEH和c++异常处理区别?

       3.C++异常处理的特点?

       4. 编译程序是如何保证在try块可以退出之前执行finally块的?


前言


结构化异常处理,SEH(Structured Exception Handling)


SEH的好处:


   就是当你编写程序时,只需要关注程序要完成的任务。如果在运行时发生什么错误,系统会发现并将发生的问题通知你。

   使用 S E H所造成的负担主要由编译程序来承担,而不是由操作系统承担。当异常块(exception block)出现时,编译程序要生成特殊的代码。编译程序必须产生一些表( t a b l e)来支持处理S E H的数据结构。编译程序还必须提供回调( c a l l b a c k)函数,操作系统可以调用这些函数,保证异常块被处理。编译程序还要负责准备栈结构和其他内部信息,供操作系统使用

   和参考。


SEH 包含两个主要功能:


   结束处理

   异常处理


   SEH和c++异常处理区别:

   不要将结构化异常处理同 C + +的异常处理相混淆。C + +异常处理是一种不同形式的异常处理,其形式是使用C + +关键字catch和throw。微软的Visual C++也支持C + +的异常处理,并且在内部实现上利用了已经引入到编译程序和 Windows操作系统的结构化异常处理的功能。


一个结束处理程序能够确保去调用和执行一个代码块(结束处理程序,termination handler),

而不管另外一段代码(保护体, guarded body)是如何退出的。结束处理程序的文法结构(使用微软的Visual C++编译程序)如下:

__try
{ //Guard body
...
}
__finally
{ // Terminal Handler
...
}


   __try和__finally关键字用来标出结束处理程序两段代码的轮廓。在上面的代码段中,操作系统和编译程序共同来确保结束处理程序中的__finally 代码块能够被执行,不管保护体(try块)是如何退出的。不论你在保护体中使用 return,还是goto,或者是longjump,结束处理程序(finally块)都将被调用。


总之,c++异常处理顺序是:

1.try 2.finally 3. try里的return或者finally之后的代码


C++异常处理的情况


情况1 释放信标情况

代码要等待信标( semaphore),改变保护数据的内容,保存局部变量dwTemp的新值,释放信标,将新值返回给调用程序。

DwORD Funcenstein1( ) {
  DWORD dwTemp;
  //1. Do any processing here.
  __try {
  //2. Request permission to access
  //protected data. and then use it.waitForSing1e0bject(g_hSem,INFINITE);g_dwProtectedData = 5;
  dwTemp = g_dwProtectedData ;
  }
  __fina1ly {
   //3.A1low others to use protected data.Re1easeSemaphore( g_hSem,1,NULL);
  }
  //4. Continue processing.
  return(dwTemp);
}

最后的释放信标放在finally 是一定会执行的。


情况2 释放信标 try中加入return

DwORD dwTemp;
    // 1. Do any processing here.:
  __try {
    // 2. Request permission to access
    // protected data, and then 'use it.
    waitForSing1e0bject(g_hSem,INFINITE);
    g_dwProtectedData = 5;
    dwTemp = g_dwProtectedData ;
    //Return the new value.
    return(dwTemp) ;
  }
  __fina1ly {
    //3.Al1ow others to use protected 
    data.Re1easeSemaphore( g_hSem,1,NULL);
  }
  // Continue processing--this code
  // wi11 never execute in this version.dwTemp = 9;
  return(dwTemp );
}

结果是,返回5。因为当提前return时,finally会先执行,然后再执行try内的return。


当return语句试图退出try块时,编译程序要确保finally块中的代码首先被执行。要保证finally块中的代码在try块中的return语句退出之前执行。Funcens tein2中,将对ReleaseSemaphore的调用放在结束处理程序块中,保证信标总会被释放。这样就不会造成一个线程一直占有信标,否则将意味着所有其他等待信标的线程永远不会被分配CP U时间。


   编译程序是如何保证在try块可以退出之前执行finally块的?

   查看总结4


情况3 释放信标 在try内使用Goto

DwORD Funcenstein3( ) {
  DwORD dwTemp;
  //1. Do any processing here.
  __try {
    //2. Request permission to access
    //protected data, and then use it.
    WaitForSingle0bject( g_hSem,INFINITE);g_dwProtectedData = 5;
    dwTemp = gdwProtectedData;
    //Try to jump over the fina11y b1ock.
    goto ReturnValue;
  }
  __fina11y {
    //3.Al1ow others to use protected data.
    Re1easeSemaphore( g_hSem,1.NULL);
  }
  dwTemp = 9;
  //4. Continue processing.Returnvalue:
  return(dwTemp);
}


结果是:goto不会执行。会先try到goto时先finally在到retunrn(dwTemp)。


当编译程序看到try块中的goto语句,它首先生成一个局部展开来执行

finally 块中的内容。这一次,在 finally 块中的代码执行之后,在 ReturnValue 标号之后的代码将执行,因为在try块和finally块中都没有返回发生。这里的代码使函数返回 5。而且,由于中断了从try块到finally块的自然流程,可能要蒙受很大的性能损失(取决于运行程序的CPU)。


情况4 释放信标 try调用函数抛异常

try块中的Funcinator函数调用包含一个错误,会引起一个无效内存访问。

DMORD Funcfurter1(){
  DWORD dwTemp;
    //1. Do any processing here.
  __try{
    //2. Request permission to access
    //protected data. and then use it.
    WaitForSing1e0bject( g_hSem,INFINITE);
    dwTemp = Funcinator( g_dwProtectedData) ;
  }
  __final1y {
    //3.A11ow others to use protected data.
    ReleaseSemaphore( g .hSem,1,NULL);
  )
  //4. Continue processing.
  return( dwTemp);
)

结果是,正常释放信标,进程不会提前结束,导致信标没释放。不然就可能引起其他进程等待。

如果结束处理程序足够强,能够捕捉由于无效内存访问而结束的进程,我们就可以相信它也能够捕捉setjump和longjump的结合,还有那些简单语句如break和continue。


情况5 循环中使用try-finally

如下代码执行结果如何?

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


总结


1.SEH(Structured Exception Handling)和SJLJ(SetJump LongJump)区别对比


SEH:

2.SEH和c++异常处理区别?

SEH和c++异常处理区别:

不要将结构化异常处理同 C + +的异常处理相混淆。C + +异常处理是一种不同形式的异常处理,其形式是使用C + +关键字catch和throw。微软的Visual C++也支持C + +的异常处理,并且在内部实现上利用了已经引入到编译程序和 Windows操作系统的结构化异常处理的功能。


3.C++异常处理的特点?

  1. 通过使用结束处理程序,可以避免 return语句的过早执行。
    例如:try内return时 finally可以避免提前返回而没有释放。


注意除了以下几种情况不能处理:


   当调用ExitThread或ExitProcess时,将立即结束线程或进程,而不会执行 finally块中的任何代码。

   另外,如果由于某个程序调用 TerminalThread或 TerminalProcess,线程或进程将死掉,finally 块中的代码也不执行。

   某些 C运行期函数(例如abort)要调用ExitProcess,也使finally块中的代码不能执行。


4. 编译程序是如何保证在try块可以退出之前执行finally块的?

   当编译程序检查源代码时,它看到在try块中有return语句。这样,编译程序就生成代码将返回值 保存在一个编译程序建立的临时变量中。编译程序然后再生成代码来执行finally块中包含的指令,这称为局部展开。更特殊的情况是,由于try块中存在过早退出的代码,从而产生局部展开,导致系统执行finall y块中的内容。在finally块中的指令执行之后,编译程序临时变量的值被取出并从函数中返回。


故在编写代码时,就应该避免引起结束处理程序的t r y块中的过早退出,因为程序的性能会受到影响。



相关文章
|
1月前
|
监控 Ubuntu Linux
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
这篇文章介绍了如何在Ubuntu和Windows系统中通过设置相同的时区并使用ntp服务来解决时间同步问题。
65 4
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
|
2月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
2月前
|
Windows
[原创]用MASM32编程获取windows类型
[原创]用MASM32编程获取windows类型
|
2月前
|
JavaScript 前端开发 API
MASM32编程通过WMI获取Windows计划任务
MASM32编程通过WMI获取Windows计划任务
|
2月前
|
API Windows
MASM32编程获取Windows当前桌面主题名
MASM32编程获取Windows当前桌面主题名
|
3月前
|
编译器 开发工具 C语言
解锁QtCreator跨界神技!Windows下轻松驾驭OpenCV动态库,让你的跨平台开发如虎添翼,秒变视觉编程大师!
【8月更文挑战第4天】QtCreator是一款强大的跨平台IDE,便于创建多平台应用。本教程教你如何在Windows环境下集成OpenCV库至Qt项目。首先,下载匹配MinGW的OpenCV预编译版并解压。接着,在QtCreator中新建或打开项目,并在.pro文件中添加OpenCV的头文件和库文件路径。确保编译器设置正确。随后编写测试代码,例如加载和显示图片,并进行编译运行。完成这些步骤后,你就能在QtCreator中利用OpenCV进行图像处理开发了。
226 6
|
3月前
|
数据库 Windows
超详细步骤解析:从零开始,手把手教你使用 Visual Studio 打造你的第一个 Windows Forms 应用程序,菜鸟也能轻松上手的编程入门指南来了!
【8月更文挑战第31天】创建你的第一个Windows Forms (WinForms) 应用程序是一个激动人心的过程,尤其适合编程新手。本指南将带你逐步完成一个简单WinForms 应用的开发。首先,在Visual Studio 中创建一个“Windows Forms App (.NET)”项目,命名为“我的第一个WinForms 应用”。接着,在空白窗体中添加一个按钮和一个标签控件,并设置按钮文本为“点击我”。然后,为按钮添加点击事件处理程序`button1_Click`,实现点击按钮后更新标签文本为“你好,你刚刚点击了按钮!”。
273 0
|
4月前
|
Linux Apache C++
FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt
该文介绍了如何在Windows环境下为FFmpeg集成SRT协议支持库libsrt。首先,需要安装Perl和Nasm,然后编译OpenSSL。接着,下载libsrt源码并使用CMake配置,生成VS工程并编译生成srt.dll和srt.lib。最后,将编译出的库文件和头文件按照特定目录结构放置,并更新环境变量,重新配置启用libsrt的FFmpeg并进行编译安装。该过程有助于优化直播推流的性能,减少卡顿问题。
127 2
FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt
|
4月前
|
存储 安全 数据安全/隐私保护
Windows 32 汇编笔记(一):基础知识
Windows 32 汇编笔记(一):基础知识
|
3月前
|
存储 编译器 Linux
Windows 32 汇编笔记(二):使用 MASM
Windows 32 汇编笔记(二):使用 MASM
下一篇
无影云桌面