`

截获所有异常 不报错

 
阅读更多

摘自:http://media.ccidnet.com/media/swm/150/15805.htm

 

【摘要】应用程序中的异常几乎是不可避免的,本文探讨了delphi的异常处理机制和异常处理的几种方法,并结合一些实例介绍如何根据应用程序的需要开发自己的异常处理程序。


  一、 异常及异常处理机制


  异常可以理解为一种特殊的事件,当这种特殊的事件发生时,程序正常的执行流程将被打断。异常处理机制能够确保在发生异常的情况下,应用程序不会中止运行,并且能以一致的风格进行处理。许多刚刚涉及delphi的程序员感觉异常处理机制高深莫测,是高级程序员的“专利”,总有尽可能绕开它的想法,因而不得不小心翼翼地检查每一次函数调用的返回值,或者通过额外的代码捕获可能的错误,即使这样,也只能保证程序代码不出错,而无法保证包括操作系统、设备驱动程序、数据库驱动程序、delphi自身的元件库和运行时间库在内的软硬件设备不出错。问题就在于,通过检查函数的返回值或设置错误陷阱只能捕获可预见的错误,如果出现没有预见到的错误,或者函数调用本身就已失败,程序正常的流程就会被打乱。由此可见,异常几乎是不可避免的。其实,object pascal提供了多种异常处理方法,使异常的处理变得轻而易举,可以将你从为你的应用程序执行的每个任务编写单独的错误处理程序的繁琐工作中解放出来。


  二、 处理异常的方法


  1. try...except 结构

  try...except 结构是这样工作的:try后面到except之前的语句通常是希望正常执行的代码,在执行过程中如果触发了异常,程序就跳入except部分。在except部分做出的处理可以有以下三种类型:

  (a) 不需要确切知道异常的类型,只需要做笼统的处理时,可以弹出一个警告信息框,或者释放已分配的资源,或者退出程序。程序示例如下:

  例1 procedure tform1.button1click(sender :tobject)

  var

  num: integer;

  begin

  try

  num:=strtoint(edit1.text);

  edit2.text:=inttostr(num*num);

  except

  showmessage(edit1.text+'无法转成整数!');

  end;

  end;

  该例中,点击button1后,程序试图将编辑框edit1中的内容转换为整型数,整数平方之后再转换成字符串类型数据,在编辑框edit2中显示。如果edit1.text是7.89,传递给strtoint将产生econverterror异常,因为7.89不是一个有效整数。异常产生后,将显示一条警告信息,并退出该过程。

  (b) 利用异常处理句柄处理某个特定的异常

  例如,在例1中可以针对econverterror异常做出如下的处理:

  例2 procedure tform1.button1click(sender :tobject)

  var

  num: integer;

  begin

  try

  num:=strtoint(edit1.text);

  edit2.text:=inttostr(num*num);

  except

  on econverterror do showmessage(edit1.text+'无法转成整数!');

  end;

  end;

  (c) 利用异常处理句柄处理多种异常

  通常,执行的代码不只产生一种异常,这就需要在except部分进行更具体的测试,根据产生的异常类型分别做出处理。现将例2稍加改动如下:

  例3 procedure tform1.button1click(sender :tobject)

  var

  num: integer;

  begin

  try

  num:=strtoint(edit1.text);

  edit2.text:=inttostr(30 div num);

  except

  on econverterror do showmessage(edit1.text+'无法转成整数!');

  on edivbyzero do

  begin

   showmessage('除数不能为零!');

   edit2.text:='0';

  end;

  end;

  end;

  在例3中,try部分的第一条语句可能产生econverterror 异常;当 num为零时,try 部分的第二条语句还会产生被零除的异常(即产生edivbyzero 异常)。由于产生异常原因不同,需要分别进行不同的处理。例3中的except 部分的代码也可以写成以下的形式,这两种异常处理的结果是一样的。

  except

  on e:exception do

  begin

   if e is econverterro then showmessage(edit1.text+'无法转成整数!');

   if e is edivbyzero then

   begin

  showmessage('除数不能为零!');

  edit2.text:='0';

   end;

  end;

  2. try...finally 结构

  try...finally 结构最大的用处是在异常发生的情况下,确保释放应用程序已经分配的资源,或者完成一些必须的操作,比如:剪贴板clipboard 在打开之后必须调用close 方法将剪贴板关闭;数据感知组件更新禁止之后必须调用enablecontrols方法才能使更新显示有效等。try...finally 结构之所以能做到这一点,是因为不管异常是否发生,程序都要执行finally 部分。请看下面的例子:

  例4 procedure tform1.button1click(sender :tobject)

  var

  icon : ticon;

  begin

  try

  icon:=ticon.create;

  icon.loadfromfile('spin.ico');

  imagelist1.replaceicon(0,icon);

  finally

  icon.free;

  end;

  end;

  在例4中,try 部分代码是从磁盘获取一个图标,用来代替imagelist1 中的0号图标。如果图标文件spin.ico 不存在或者被损坏,将会产生efopenerror 异常,中断 try 部分代码的执行,但是程序会执行finally 部分的代码,使得icon 占用的资源得以释放。当然,如果没有发生任何异常,finally 部分也将被执行。可以说,finally 部分是 try...finally 结构的“必经之路”。

  3. try...except 与try...finally 的嵌套结构

  try...finally 结构确实有它独到的功能,但是try...finally结构中没有 try...except 结构中的异常处理句柄,也就无法知道当前确切的异常类型,并且不论异常是否发生,程序都执行 finally 部分,这就决定了 try...finally 结构无法对发生的异常进行特别的处理。如果在应用程序中,既需要完成一些必要的操作,又要对发生的异常进行处理,那么最好使用这两种结构的嵌套。请看下例:

  例5 procedure tform1.button1click(sender :tobject)

  var

  icon : ticon;

  begin

  try

  try

   icon:=ticon.create;

   icon.loadfromfile('spin.ico');

   imagelist1.replaceicon(0,icon);

   finally

   icon.free;

   end;

  except

   on efopenerror do showmessage('无法打开图标文件spin.ico');

  end;

  end;

  在例5中,无论异常发生与否,都将执行finally 部分释放图标占用的资源。一旦异常发生,则产生警告信息。上例是在 try...except 结构的 try 部分嵌套 try...finally 结构,也可以在 try...finally 结构的 try 部分嵌套 try...except 结构,前者是先执行必须的操作,再进行异常的处理,而后者是先进行异常的处理,再执行必须的操作。在多数情况下,两者的区别并不大。除此之外,try...except 结构和try...finally 结构还可以各自嵌套。在复杂的应用程序中,except 部分或finally部分的异常处理代码本身又有可能触发异常,这就需要采用嵌套结构编写更深一层的异常处理代码,这里就不再详细举例了。

  4. 定义自己的异常类

  我们的探讨将进入更深的一层——定义自己的异常类。虽然在简单的应用程序中,程序员并无太大必要定义自己的异常类,但是它对编写个性化的异常处理程序仍然是有帮助的。例7中的过程是对数据集 table1 中的字段name进行合法性检查,如果name 没有值或为空字符串,则产生异常,这其中就定义了一个 exception 的派生类emyexception。

  例6

  type emyexception=class(exception); {定义自己的异常类emyexception}

  procedure tform1.table1namevalidate(sender : tfield);

  begin

  if ( sender.isnull ) or ( sender.asstring='') then

   raise emyexception.create('必须填写名称');

  end;


  三、个性化的异常处理句柄


  delphi会自动处理大部分的异常,但全英文信息提示会让应用程序的最终用户感觉并不友好。那么如何编写自己的异常处理代码呢? 在forms单元中声明的tapplication 类中的onexception 事件为编写自己的异常处理代码提供了可能。事实上,用于onexception 事件的事件句柄就是应用程序默认的异常处理句柄。请看下面的例子。

  在 project resource 中,首先创建一个新类 tmyclass, tmyclass 中有一个myexceptionhandler 方法,可以根据应用程序的需要来编写,这里体现了个性化的异常处理。由myexceptionhandler事件来响应application 的 onexception事件,这样在程序发生异常时,首先调用的就是自己编写的异常处理事件myexceptionhandler事件。工程文件如下:

  例7

  program exceptprj;

  uses

   forms, windows, sysutils, classes, dialogs, db, dbtables,

   example in 'example.pas' {form1};



  {创建一个tobject的派生类tmyclass}

  type

   tmyclass=class(tobject)

   public

   procedure myexceptionhandler(sender: tobject; einstance: exception);

   end;

  {编写自己的异常处理句柄}

  procedure tmyclass.myexceptionhandler(sender: tobject; einstance: exception);

  var

   errorfile:textfile;

   filename,content:string;

   findflag:boolean;

  begin

  {截获出现的新的异常,并存入文件errorinfo.txt.}

   filename:=applicationpath+'errorinfo.txt'; { applicationpath 是在主form中定义的全局变量,记录应用程序所在的目录}

  {打开文件}

   assignfile(errorfile,filename);

   if not fileexists(filename) then

   rewrite(errorfile)

   else

   reset(errorfile);



  {检查出现的异常是否曾经记录在文件errorinfo.txt中}

   findflag:=false;

   while not seekeof(errorfile) do

   begin

   readln(errorfile,content);

   if pos(einstance.classname+':'+einstance.message,content)<>0 then

   begin

   findflag:=true;

   break;

   end;

   end;

  {如果是一个未被记录过的异常,则将它记录在文件中}

   if not findflag then

   begin

   showmessage('出现新的错误!');

   append(errorfile);

   writeln(errorfile,einstance.classname+':'+einstance.message);

   end;

  {关闭文件}

   closefile(errorfile);

  

  {对出现的异常显示中文提示}

   if einstance is edivbyzero then

   application.messagebox('除数不能为零!','错误',mb_ok+mb_iconstop)

   else if einstance is eaccessviolation then

   application.messagebox('访问了无效的内存区域!','错误',mb_ok+mb_iconstop)

   else if (einstance is edatabaseerror) then

   application.messagebox('数据库操作出现错误!','错误',mb_ok+mb_iconstop)

   else if (einstance is efopenerror) then

   application.messagebox('文件不能打开!','错误',mb_ok+mb_iconstop)

   else if (einstance is econverterror) then

   application.messagebox('非法的类型转换!','错误',mb_ok+mb_iconstop)

   else

   messagedlg(einstance.classname+':'+einstance.message,mtinformation,[mbok],0)

  end;



  {$r *.res}



  var

   myobject: tmyclass; {声明tmyclass类的一个变量}



  begin

   application.initialize;

   application.createform(tform1, form1);

   applicationpath:=extractfilepath(application.exename);



   myobject:=tmyclass.create; {创建tmyclass类的一个实例}

   application.onexception:=myobject.myexceptionhandler; {响应onexception事件}



   application.run;

  end.

  例7中的myexceptionhandler 事件是我们在开发铁路车站行车工作细则管理系统时编制的,由于篇幅所限,在此仅将这一事件的整体框架呈现给大家,希望通过这个例子来说明开发异常处理句柄的方法。



  到此为止,我们对delphi异常处理的几种方法由浅入深地进行了归纳,并对应于各种方法列举了实例,希望对异常处理怀有“胆怯”心理的编程朋友有所帮助。当然,在遇到具体问题的时候,还需要您选择最适合的异常处理方法。

分享到:
评论

相关推荐

    C# .net Aop 动态截获异常

    通过以上步骤,我们可以实现在不修改原始代码的情况下,动态地为方法添加异常处理逻辑。这不仅可以提高代码的整洁度,还能方便地在整个应用程序中统一异常处理策略。 在提供的"ExinScada.Aop"压缩包中,可能包含了...

    在vc中实现应用程序的异常截获

    异常截获是指在程序中设置特定的处理程序,以便在出现错误或异常时能够捕获并处理它们,而不是让程序崩溃。这篇文档将详细探讨如何在VC++中实现应用程序的异常截获。 首先,我们需要了解C++的异常处理基础。C++的...

    鼠标键盘事件截获

    这意味着,如果要在所有进程中截获事件,需要在系统全局范围(例如,从服务或后台进程中)安装钩子。 9. **安全与兼容性问题**: 全局钩子可能影响其他应用程序的性能,因此应当谨慎使用。此外,系统权限和反作弊...

    测绘资料-百度地图截获器(矢量版)1.0Bete(刘俊环版权所有).zip

    测绘资料-百度地图截获器(矢量版)1.0Bete(刘俊环版权所有).zip 这个压缩包文件主要包含了用于测绘领域的工具——百度地图截获器的一个版本,具体为矢量版的1.0Beta。这个工具是由刘俊环个人开发并拥有版权,它...

    iphone 异常截获

    标题“iPhone异常截获”指的是在iOS开发过程中,如何捕获和处理运行时出现的异常情况,这通常涉及到编程错误或者不可预见的用户行为。在iOS应用开发中,尤其是使用Objective-C或Swift语言时,正确地处理异常是保证...

    利用WM_SYSMSGFILTER钩子截获系统所有的消息(改良版1).visual c++

    总之,“利用WM_SYSMSGFILTER钩子截获系统所有的消息(改良版1)”是一个涉及Windows编程底层机制的项目,它要求开发者对Windows消息机制有深入的理解,并能够熟练运用Visual C++进行系统级别的编程。通过这种方式,...

    雷达信号截获与分析

    ### 雷达信号截获与分析 #### 一、引言 《雷达信号截获与分析》一书由雷达信号领域著名专家、IEEE会员Richard G. Wiley博士撰写,是国防电子信息技术丛书中的一本重要著作。该书系统地介绍了雷达电子对抗中的关键...

    易语言程序异常处理源码.rar

    开发者可以通过`catch`语句捕获特定类型的异常,或者使用`catch...else`来捕获所有未被特定`catch`块处理的异常。此外,易语言还提供了`finally`关键字,用于在无论是否发生异常的情况下都需要执行的清理代码,如...

    vc++通过钩子截获exe收到的所有消息.zip

    本资源"vc++通过钩子截获exe收到的所有消息.zip"提供了一个使用Visual C++实现的示例,展示了如何通过钩子函数来截获并处理一个可执行文件(exe)接收到的所有消息。 首先,让我们了解一下钩子(Hook)的基本概念。...

    网络封包截获器 易语言源码

    封包截获器通过操作系统提供的网络接口(如WinPCap或Libpcap)来捕获这些数据包,不改变其原有的流向,只是默默地观察和记录。这种“嗅探”技术是网络分析、安全检测和性能优化的基础。 易语言,作为一种中文编程...

    IP 数据包截获

    例如,`tcpdump -i eth0 host 192.168.1.1` 将捕获与指定IP地址(192.168.1.1)通信的所有数据包。 在网络安全方面,IP数据包截获有助于检测潜在的入侵和攻击。例如,通过对网络流量的实时监控,可以发现异常的连接...

    网络数据截获

    总的来说,网络数据截获在Java中实现并不复杂,关键在于理解网络协议和数据包结构,并选择合适的库来实现。通过这个技术,开发者可以深入洞察网络行为,从而提升应用性能,排查网络问题,甚至增强系统安全性。

    截获Linux操作系统异常处理

    在某些情况下,我们可能需要去截获Linux操作系统的一些异常处理,比如截获page fault异常处理。  可以修改内核的情况下:  如果我们能够修改内核,那么截获page fault异常处理会非常简单。以linux 3.8.0内核为...

    简单的网络端口文本数据截获

    UDP则是一种无连接的、不可靠的协议,它不保证数据包的顺序或完整性,但具有更高的传输速度。在Delphi中,我们可以使用UDPServer和TUDPClient组件来处理UDP通信。UDPServer监听特定端口,接收到数据后触发事件;...

    windows防火墙与网络封包截获技术.part1

    windows防火墙与网络封包截获技术 请烦劳再下载part2部分,由于上传文件不能大于10M。。。。 第一章 windows网络协议架构 第二章 编程环境VC构建 第三章 用传输层过滤驱动程序截获网络封包 第四章 用...

    c++编写acm之密码截获

    在这个问题中,“密码截获”是一个典型的算法挑战,常见于国际大学生程序设计竞赛(ACM,International Collegiate Programming Contest)中。ACM比赛旨在锻炼学生的算法设计、编程和问题解决能力。这类问题通常涉及...

    windows防火墙与网络封包截获技术.part2

    windows防火墙与网络封包截获技术 请烦劳再下载part1部分,由于上传文件不能大于10M。。。。 第一章 windows网络协议架构 第二章 编程环境VC构建 第三章 用传输层过滤驱动程序截获网络封包 第四章 用...

    MediaBox(截获视频流)

    MediaBox 截获视频流 开始: 1、解压以上工具,接着打开名字为“MediaBox”的软件,这是一个截获视频流的... ” 再加刚才那个视频格式,当然有些后面已经有视频格式的就可以不加。这样就得到一个完整的电视直播源。

    论文研究-基于API截获的软件行为监控技术 .pdf

    API截获技术的优势在于它不需要修改源代码、重新编译和连接,也不需要替换任何动态连接库,从而实现了对应用程序和操作系统环境的透明监控。此外,该技术还可以实现分线程实时显示日志信息,使用户能够即时了解软件...

Global site tag (gtag.js) - Google Analytics