将一个vcl对象的事件指向一个普通过程或函数,可还有一点问题,请大家想想. (100分)

  • 主题发起人 主题发起人 lynu
  • 开始时间 开始时间
L

lynu

Unregistered / Unconfirmed
GUEST, unregistred user!
//经测试,可以在事件发生时得到执行,但访问函数参数多数出错(第一个参数好象正常

uses typinfo,...;

procedure SetEventToProc(Sender:TObject;evenname:string;e:Pointer);
var
m:TMethod;
begin
//将一个vcl对象的事件指向一个普通过程或函数
m.Code:=e;
m.Data:=Sender;
try
SetMethodProp(Sender,evenname,m);
except
end;
end;

//测试代码
procedure CloseQuery(Sender: TObject
var CanClose: Boolean);
begin
ShowMessage(TForm(Sender).Caption);//正确
//CanClose:=true;//访问非法,未知何因
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
SetEventToProc(Sender,'OnCloseQuery',@CloseQuery);
end;
 
不懂。不过想想可能时不了解delphi的参数传递方式吧。
 
刚刚打了半天,没有能够保存:(
我想也是因为var传入的问题吧,我想var Delphi并不是简单的传入地址的。
还有你这个函数是普通函数,会不会也是造成使用Var传入的参数不能被正常修改的原因?
我测试的结果是,如果直接写CloseQuery,ShowMessage出来为1,而如果用你的方法,结果
为52!(不知道会不会是对象的跟普通的代码不放在一起,正如汇编中的near与far造成的)
另有一个奇怪的问题就是:
procedure CloseQuery(Sender: TObject
var CanClose: Boolean);
begin
CanClose:=true;//访问非法,未知何因
end;
我用以下代码代替,结果出错信息竟然不一样!
procedure CloseQuery(Sender: TObject
var CanClose: Boolean);
type
PBoolean = ^Boolean;
var
B: PBoolean;
begin
B := PBoolean(CanClose);
B^ := True;
end;
不知是何道理?
 
那是因为属于类的方法还有一个隐藏参数 Self 的缘故吧:)
于是产生了参数传递的错位:

(类的方法) Self Sender CanClose
| |
(普通过程) Sender CanClose

于是你使用 Sender 没有错是因为此时 Sender 和 Self 指向相同的地址(同一实例)
但是你使用 CanClose 就相当于使用 Sender,所以出错

以上均属推测,没有试验:) 参见我的帖子:lid=1289838
 
楼上说得很有道理,我怎么没有想到呢?!:(
顶楼的,你这么写就完全执行正确了!
procedure CloseQuery(Sender: TObject
var X,CanClose: Boolean);//增加一个参数
begin
ShowMessage(TForm(Sender).Caption);//正确
CanClose:=true;//访问非法,未知何因
end;
 
shenloqi: 你这样的确可以正确执行,不过还是有问题,你不应该使用第一个参数
这里是因为原来的第一个参数是 Sender,刚好和 Self 指向相同实例,如果原来的
第一个参数是其他的类型,你这样使用就会出问题。应该增加声明的那个参数应该
放在第一位,而且不是 var Boolean 型,而是 TObject 型。当然可以声明为其他
相兼容的类型,如 Pointer 或 DWord。
新的定义如下:

procedure CloseQuery(Instance: TObject
Sender: TObject
var CanClose: Boolean);
// ~~~~~~~~~~~~~~~~增加为第一个参数!
begin
ShowMessage(TForm(Sender).Caption);
// 现在的 Sender 是第二个参数,即原来的第一个,这才正确
CanClose:=true;
end;
 
Beta弟弟(想来你比我小,我这个年纪还在写代码的比较少),厉害,佩服.
 
procedure AppException(Instance: TObject
Sender: TObject
E:Exception);
begin
ShowMessage(Instance.ClassName);
ShowMessage(Sender.ClassName);
ShowMessage(E.Message);
end;

好象这样不行
SetEventToProc(Application'OnException',@AppException);
但这样可以
SetEventToProc(ApplicationEvents1,'OnException',@AppException);
第一句时会抛出一个非法访问的异常,跟踪到typinfo.pas里,发现运行到
procedure SetMethodProp(Instance: TObject
PropInfo: PPropInfo;
const Value: TMethod)
assembler;
asm
...
时,PropInfo是nil.
不知各位没有有试过?
 
楼主:
听说你有<Delphi 5.X ADO/MTS/COM+高级程序设计篇 >的完整电子版
能否上传一下啊?

谢谢了
 
后退
顶部