- 浏览: 2011121 次
- 性别:
- 来自: 厦门
文章分类
- 全部博客 (1409)
- asp/asp.net学习 (241)
- oracle (10)
- delphi (295)
- java (27)
- pb (1)
- 每日点滴 (49)
- 学习方法 (40)
- 思想方面 (104)
- C语言 (5)
- C++ (1)
- 代码重构经验 (5)
- 软件工程 (3)
- 数据库 (99)
- 英语学习 (3)
- mysql (1)
- 该关注的网站或者网页 (42)
- 总结 (7)
- 要去做的事情 (33)
- 算法 (1)
- 网络方面 (29)
- 随感 (96)
- 操作系统 (36)
- UML (12)
- 常用工具的使用 (55)
- 脚本 (7)
- 汇编 (62)
- 数据结构 (2)
- 财务 (38)
- 语文作文 (16)
- 法律 (1)
- 股票 (88)
最新评论
-
devwang_com:
可以,学习了~~
列出文件夹下所有文件夹的树形结构--Dos命令 tree的使用 -
hvang1988:
不管用啊 frxrprt1.PreviewForm.Pare ...
fastReport预览时嵌入到别的窗体 -
00915132:
我也有这个疑问,非常 感 谢
left join加上where条件的困惑 --SQL优化 -
zhuyoulong:
学习了,高效读书
软件架构师要读的书 -
nTalgar:
非常感谢分享!
Application.ProcessMessages用法:
截获所有异常 不报错
- 博客分类:
- delphi
摘自: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异常处理的几种方法由浅入深地进行了归纳,并对应于各种方法列举了实例,希望对异常处理怀有“胆怯”心理的编程朋友有所帮助。当然,在遇到具体问题的时候,还需要您选择最适合的异常处理方法。
发表评论
-
form打开时的关闭代码
2011-10-25 20:29 1524摘自:http://topic.csdn.n ... -
TUpdateSQL更新问题 提示Update Failed
2011-08-29 20:26 1201摘自:http://topic.csdn.net/u/200 ... -
图解如何用Eurekalog跟踪程序错误
2011-08-12 07:28 910图解如何用Eurekalog跟踪程序错误 摘自:h ... -
VirtualBox 复制VDI 并能创建新的虚拟机
2011-07-21 11:14 2691摘自:http://www.nonabyte.net/how- ... -
delphi exe程序以及DLL程序如何在模块内部获得各自的路径
2011-07-11 16:38 1273delphi Exe程序以及DLL程序如何在模块内部获得各自的 ... -
Delphi文本文件读写
2011-07-11 14:55 1183Delphi文本文件读写 (2008-10-31 1 ... -
Delphi自定义的消息的使用
2011-05-31 14:12 2273阅:已验证,可通过; 摘自:http://blog.1 ... -
怎么查看OutputDebugString输出的信息?debugview
2011-05-25 16:02 3803网上很多说用debugview查看,我自己写了一个程序,里面用 ... -
Delphi里查看该变量的内存值
2011-05-25 13:32 1094Delphi里查看该变量的内存值:Run==>Evalu ... -
注册表操作 写入autorun启动项,键值为本程序的全路径
2011-05-20 15:40 1786procedure TForm4.Button2Click ... -
报说包frx7和frxdb7都包含了某个单元的错误
2011-05-11 09:59 9821. 问题描述:在安装FastReport3的时候,安装到- ... -
Delphi中使用ListView和TreeView的Item中的Data可能被忽略的内存泄漏
2011-05-03 14:34 1431摘自:http://blog.csdn.net/g ... -
WM_USER的说明 用户消息ID
2011-04-28 10:46 1645WM_USER 摘自:http://baike.bai ... -
ToolButton不能改变大小
2011-04-28 10:38 3434问题描述:ToolButton不能改变大小? 问 ... -
Delphi里TOOLBAR 上的button的caption为什么显示不出来啊
2011-04-20 17:55 1710Delphi里TOOLBAR 上的button的caption ... -
delphi指针简单入门
2011-04-11 21:42 1119摘自:http://topic.csdn.net/t/2003 ... -
Delphi中paramstr的用法 应用程序间传递数据
2011-04-01 14:33 2050Delphi中paramstr的用法 应用程序间传递数据 ... -
Delphi中的THashedStringList对象 --大数据量时
2011-04-01 13:54 5101Delphi中的THashedStringLi ... -
inherited Create(AOwner); 和直接写inherited有区别吗
2011-03-26 15:44 1286摘自:http://zhidao.baidu.com/que ... -
delphi中的Create,Send,Sender,Self
2011-03-26 14:08 1424摘自:http://www.cnblogs.com/keyco ...
相关推荐
利用特性,绑定上下文,代理,反射等技术动态截获异常,实现切面编程
利用WM_SYSMSGFILTER钩子hook截获系统所有的消息(改良版1).visual c++
这是一个如何在window CE 5.0 下截获系统键盘消息的示例,在window CE 5.0 一般不支持全局的钩子函数,但是键盘钩子是个例外,这个程序经过测试,并在项目中有使用。
测绘资料-百度地图截获器(矢量版)1.0Bete(刘俊环版权所有).zip
在某些情况下,我们可能需要去截获Linux操作系统的一些异常处理,比如截获page fault异常处理。 可以修改内核的情况下: 如果我们能够修改内核,那么截获page fault异常处理会非常简单。以linux 3.8.0内核为...
windows防火墙与网络封包截获技术 请烦劳再下载part2部分,由于上传文件不能大于10M。。。。 第一章 windows网络协议架构 第二章 编程环境VC构建 第三章 用传输层过滤驱动程序截获网络封包 第四章 用...
网络数据截获java,学习下怎样,通过网卡获取数据包
vc++通过钩子截获exe收到的所有消息.zip visual c++ hook所有消息
windows防火墙与网络封包截获技术 请烦劳再下载part1部分,由于上传文件不能大于10M。。。。 第一章 windows网络协议架构 第二章 编程环境VC构建 第三章 用传输层过滤驱动程序截获网络封包 第四章 用...
MediaBox 截获视频流 开始: 1、解压以上工具,接着打开名字为“MediaBox”的软件,这是一个截获视频流的... ” 再加刚才那个视频格式,当然有些后面已经有视频格式的就可以不加。这样就得到一个完整的电视直播源。
本人在QQ讨论群整理的,大家互相学习学习
程序将系统中的所有进程显示出来,然后等待用户进行选择,对用户选择的进程进行注入,挂钩网络函数,此后目标进程对网络函数的调用就变成了对本程序提供的代理函数的调用。对用户怀疑的进程进行监视,将其发送到...
在WIN32平台下截获鼠标和键盘事件,很好的一个例子
http网络数据包截获与还原
vc钩子hook 截获exe调用的任何函数.api拦截
用c++编写的acm之密码截获问题。可以参考着用下。
换点资源分,delphi2007,可以截获UDP TCP 客户端和服务端发送文本文件
VisualC 实效编程 114 截获键盘信息VisualC 实效编程 114 截获键盘信息VisualC 实效编程 114 截获键盘信息VisualC 实效编程 114 截获键盘信息VisualC 实效编程 114 截获键盘信息VisualC 实效编程 114 截获键盘信息...
webscarab 做代理,HTTP截获,安全攻击