通用Delphi异常处理方法
1. 引言
软件无论在测试中,还是常规运行时,都不可避免会发生由于软件设计、编码或操作人员非法操作,抑或数据库、网络线路等软硬件错误而引发应用程序异常。对运行时出现的异常处理,通常由操作人员记录异常信息或者口头陈述,反馈给软件设计编程人员。这样一方面造成反馈信息不够清晰完整,另一方面造成信息反馈不及时,造成效率不高。如果应用程序能够自动捕捉到异常信息,并详细记录保存下来,这就可避免出现上述问题,并且还有利于软件质量的分析评价。
2. Delphi异常处理机制
软件运行时的异常按编程人员是否作了专门处理可分为专门处理的异常和Delphi默认处理的异常。专门处理的异常一般是用Try……Except结构语法来实现,Except部分的代码处理Try后面到Except之前的语句中触发的异常。对这种异常很容易把它的触发原因、模块、操作、时间等记录保存下来。也可以用Try……Finally结构语法来实现,但只能作笼统处理。 当应用程序出现异常时,如果应用程序没有专门处理异常,Application实例会自动调用HandleExcept方法,HandleExcept方法首先查找应用程序有没有Application实例中的onExeption事件,若有就执行响应这个事件的代码,如果没有,就自动调用Application实例中的ShowException方法,ShowException方法将推出一个提示窗口显示有关异常信息。Sysutils单元中声明了一个Exception类,这个类有一个Message属性,关于当前异常的信息就储存在这个属性中。因此可以用自己的代码代替默认的异常处理句柄,办法就是响应OnException事件。Object pascal规定,响应OnException事件的句柄必须是一个方法,并且此方法的首部必须与TExceptionEvent类型完全一致,在Forms单元中,TExceptionEvent类型是这样声明的: TExceptionEvent=Procedure(Sender:Tobject;E:Except) of Object;
3. 应用实例
下面用实例介绍如何用自定义的提示窗口代替默认提示窗口,如何获得触发异常的模块窗口标题、类名、原因等。提示窗口界面如图1所示。
unit MyErrorMessage; interface ….. type TFrm_ErrorMessage = class(TForm) …… procedure MyErrorMessage(Sender:TObject;E: Exception); //定义代替OnException事件的句柄 procedure FormCreate(Sender: TObject); private …… File_Name:String;//保存异常信息的文件名 public end; var Frm_ErrorMessage: TFrm_ErrorMessage; implementation …… procedure TFrm_ErrorMessage.MyErrorMessage(Sender: TObject; E: Exception); var F: TextFile; //Text类型文件的句柄 SaveMessage:String; //代保存的异常信息 FrmHandle:Integer; //触发异常模块所在的窗口句柄 Ls_Title:array[0..254] of Char; //触发异常模块所在的窗口的标题 begin if e is EConvertError then //判断异常类型 Label1.Caption:='输入的数据类型错误' else if e is EDatabaseError then Label1.Caption:='数据库错误' …… else Label1.Caption:='系统错误!' ; end; FrmHandle:=GetactiveWindow(); //获取触发异常模块所在的窗口句柄(活动窗口句柄) if FrmHandle< > Null then if GetWindowText(FrmHandle,Ls_Title,255)> 0 then //获取异常模块所在的窗口的标题 SaveMessage:= StrPas(Ls_Title) else SaveMessage:='无标题'; //记录窗口的标题 Try // 把异常信息保存到数据库表(AppError)中,可能再次触发异常 If Not QureyAppError.Active then QureyAppError.Active:=true;//打开数据集 QureyAppError.AppendRecord([Label1.caption,StrPas(Ls_Title),Sender.ClassName,now, e.Message]); //把触发异常的类型,窗口标题、类名、时间、异常原因保存到数据库中 QureyAppError.post; Except //如果触发错误,则把错误信息保存到文件中 SaveMessage:=Label1.caption; //记录异常类型 SaveMessage:=SaveMessage+' '+Sender.ClassName; //记录异常模块所在的类名 SaveMessage:=SaveMessage+' '+FormatDateTime('yyyy-mm-dd hh:ss ',now);//时间 SaveMessage:=SaveMessage+' '+e.Message; //记录异常原因 Try //文件操作可能再次触发异常 if not FileExists(File_Name) then FileClose(FileCreate(File_Name));//创建保存异常信息文件 AssignFile(F,File_Name); //打开文件 Append(F); //设置增加的模式 Writeln(F, SaveMessage); //把异常信息追加到文件中 CloseFile(F); //关闭文件 Finally End; End; Frm_ErrorMessage.ShowModal; //显示提示窗口 end; procedure TFrm_ErrorMessage.FormCreate(Sender: TObject); begin ……. Application.OnException:=Frm_ErrorMessage.MyErrorMessage; //代替默认的异常处理句柄 File_Name:=ExtractFilePath(Application.ExeName)+ChangeFileExt(ExtractFileName(Application.E xeName),'.txt'); //设置保存异常信息的文件名为应用程序文件名,但改变后缀为'.txt' end; end.
4. 结束语
把异常信息保存在数据库(保存在文件里的,也导入数据库中),使信息反馈及时、详细和准确,有利于编写测试修改报告,便于分析评价软件质量。特别是对这些信息进行统计分析,可以获得很多有用信息,如哪些模块发生的错误很多,哪类错误经常发生等等。通过定义自己的异常类,把专门处理的异常信息通过再次触发异常,最后由上述通用异常处理代码处理,则可减轻编程工作量,这也符合面向对象编程的思想。
参考文献 1 徐新华 Delphi3 编程指南(上编) 北京: 宇宙出版社 1998.6 2 张海潘 软件工程导轮(第三版) 北京: 清华大学出版社 1998.1
|