S
shenloqi
Unregistered / Unconfirmed
GUEST, unregistred user!
线程中的异常会导致应用程序的异常终止,所以应当在线程中捕捉异常,并用另一种方式
把这个异常通知给应用程序的主线程。
如果你希望主线程接受实际的异常对象,而不只是捕捉异常消息(如果只是要显示消息,
只需要把消息字符串传递给主线程,然后在主线程中用对话框显示出来就可以了),就需
要做类似下面的处理工作。因为当一个try...except...end块完成异常处理时,Delphi会
自动释放这个异常对象,所以下面的工作就是截取异常对象,把它传递给主线程,并防止
Delphi过早的释放他(修改运行时堆栈上的异常帧来瞒过Delphi ^.* ),这个方法是将
线程过程包裹在try...except...end块之内,传递给线程函数的参数是指向对象引用的指
针(Param: Pointer),函数可以把一个异常对象存放在该对象引用上,如果成功则存放
nil。
把这个异常通知给应用程序的主线程。
如果你希望主线程接受实际的异常对象,而不只是捕捉异常消息(如果只是要显示消息,
只需要把消息字符串传递给主线程,然后在主线程中用对话框显示出来就可以了),就需
要做类似下面的处理工作。因为当一个try...except...end块完成异常处理时,Delphi会
自动释放这个异常对象,所以下面的工作就是截取异常对象,把它传递给主线程,并防止
Delphi过早的释放他(修改运行时堆栈上的异常帧来瞒过Delphi ^.* ),这个方法是将
线程过程包裹在try...except...end块之内,传递给线程函数的参数是指向对象引用的指
针(Param: Pointer),函数可以把一个异常对象存放在该对象引用上,如果成功则存放
nil。
代码:
//PExceptionRecord是Windows.pas中导入的
uses Windows;
type
//指向TObject的指针
PObject = ^TObject;
//指向TRaiseFrame的指针
PRaiseFrame = ^ TRaiseFrame;
//记录类型的TRaiseFrame
TRaiseFrame = record
//RaiseList函数返回的是指针,所以NextFrame也应该是指针
NextFrame: PRaiseFrame;
ExceptAddr: Pointer;
ExceptObject: TObject;
ExceptionRecord: PExceptionRecord;
end;
{-----------------------------------------------------------------------------
Procedure: ThreadFunc
Author: slq
Date: 22-三月-2002
Arguments: Param: Pointer
Result: Integer
Purpose: 展示如何在线程中捕获异常
这个函数捕捉异常并把他们放到Param^中,
如果不产生异常则返回nil。
-----------------------------------------------------------------------------}
function ThreadFunc(Param: Pointer): Integer;
var
RaiseFrame:PRaiseFrame;
begin
Result := 0;
PObject(Param)^ := nil;
try
//这里是这个线程函数的主体执行代码
//
//TODO: HereIsRealWork
except
//如果RaiseList为nil表示没有异常,否则RaiseList返回指向
//一个TExceptionFrame记录
RaiseFrame := RaiseList;
if RaiseFrame <> nil then
begin
//当线程抛出异常时,保存异常对象到RaiseFrame.ExceptObject,
//设置这个异常对象的引用为nil,Delphi就不会过早的释放异常对象。
//
//这里涉及到引用计数方面的内容,需要对引用计数比较熟悉。
//用类似的方法可以实现使得string等等Delphi原先自动引用计数
//的类型不过早的释放以完成特殊的效果。
PObject(Param)^ := RaiseFrame.ExceptObject;
RaiseFrame.ExceptObject := nil;
end;
end;
end;