DELPHI自定义事件处理

为什么我们点击按钮,就会执行按钮的onclick事件?这个事件是怎么和我们自己的代码关联起来的。相信很多人都有这个疑问。那么我们就通过一个自定义事件来了解这里面得运行原理。以乘法运算来显示,如果乘数大于100,就提示用户,太大了。这个事件用自定义事件定义。 大家先看一下最终效果,

我添加了三个文本框,一个按钮,当第一或者第二个文本框的数>100时,点求积按钮,提示Too Big 对话框。

完成自定义事件需要5步来做:

1.定义TNotifyEvent类型私有变量

FTooBig:TNotifyEvent;

 

FTooBig是一个指针,它可以保持事件方法的调用地址。

2.公布一个属性

published
  property OnTooBig:TNotifyevent read FTooBig write FTooBig;

 

OnTooBig这个属性用来操作FTooBig这个私有变量,因为FTooBig是个函数指针,所以但读这个变量时,也就调用了函数。

3.定义事件处理函数

procedure TooBigEvent(Sender: TObject);

         procedure TForm1.TooBigEvent(Sender: TObject);
         begin
         Application.MessageBox('Too Big','Test Event!',MB_OK);
         end;

 

这是当文本框数太大时执行的方法。

4. 把事件处理函数赋值给TNotifyEvent私有变量

FTooBig := TooBigEvent;

5. 当条件符合时执行事件处理函数

procedure TForm1.Button1Click(Sender: TObject);
var
  val1 : integer;
  val2 : integer;
  res  : integer;
begin
 val1 := StrToInt(Edit1.Text);
 val2 := StrToInt(Edit2.Text);
 if(val1<100)and(val2<100) then
 begin
 res := val1*val2;
 Edit3.Text := IntToStr(res);
 end
 else
 if assigned(FTooBig) then OnTooBig(Self);
end;

下面贴出全部代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Button1: TButton;
    procedure TooBigEvent(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private

     FTooBig:TNotifyEvent; 
    { Private declarations }
  public
    { Public declarations }
  published
    property OnTooBig:TNotifyevent read FTooBig write FTooBig;
end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  val1 : integer;
  val2 : integer;
  res  : integer;
begin
 val1 := StrToInt(Edit1.Text);
 val2 := StrToInt(Edit2.Text);
 if(val1<100)and(val2<100) then
 begin
 res := val1*val2;
 Edit3.Text := IntToStr(res);
 end
 else
 if assigned(FTooBig) then OnTooBig(Self);
end;
procedure TForm1.TooBigEvent(Sender: TObject);
begin
Application.MessageBox('Too Big','Test Event!',MB_OK);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FTooBig := TooBigEvent;
end;

end.

 

几种典型程序Button处理代码的定位

首先
1 od 下运行程序,F12 暂停;
2 View菜单中选击Windows项,在打开的窗口中可以从Title栏看到目标按钮,从而找到它的Handle(xxxxxxxx) ;

对不同平台生成的程序,分别处理:

一、VB, Delphi, CBuilder 程序:
3 在CallWindowProcA入口下条件断点: [esp+8]==xxxxxxxx && [esp+0c]==202;
4 F9继续程序,点击目标按钮,程序中断;
5 Alt+F4,在代码段(.text)上下访问断点;
6 F9执行程序,程序中断,
1). VB程序中断在下面代码
PUSH DWORD PTR DS:[EAX+EBX]              ; yyyyyyy
上面[EAX+EBX]的值(yyyyyy)就是我们要找的位置。

2). Delphi, CBuilder 的程序
程序直接断在我们要找的位置。

借moon一句,这姑妄称作CallWindowProcA条件断点加上code段内存断点法吧。

二、VC程序
又分MFC和Win32两种情况,二者相同之处:
3 在IsDialogMessageW入口下条件断点: [[esp+8]]==xxxxxxxx && [[esp+8]+4]==202
4 F9继续程序,点击目标按钮,程序中断;
5 Alt+F4,在代码段上下访问断点;
6 F9执行程序,程序中断, 注意这里虽然中断在code段,但却不是处理Button点击事件的代码处
这时:
对Win32程序,只需要按几下F7,当回到User32.dll领空后再重复一次第 5、6步就可以了;
而对于MFC程序,我们不得不多次重复这样的操作:单步回到MFC领空,再第 5、6步。好在已经看到大陆啦!

类比,这就叫IsDialogMessageW条件断点加上code段内存断点法了。

敬请各位指正。

Delphi/C#之父:Anders Hejlsberg

Anders Hejlsberg曾在丹麦科技大学学习工程学,他编写的Pascal编译器的核心,1981年将Pascal编译器卖给了Borland,并加入Borland公司,那时的Borland公司还是一个名不见经传的小公司。

Anders Hejlsberg在Borland主持开发了Turbo Pascal,Turbo Pascal获得一直好评,Anders Hejlsberg并未止步不前,他将Turbo Pascal编程一种面向对象的、拥有可视化环境和卓越的数据库访问特性的应用程序开发语言-Delphi。

Java出现了。Anders Hejlsberg在Borland一直郁郁不得志,据Borland内部人士讲Anders Hejlsberg认为自己不再是不可或缺的人。比尔盖茨慧眼识才,三故茅庐,把Anders Hejlsberg请到了微软。最开始微软许以重金,但Anders Hejlsberg不为所动,当清楚Anders Hejlsberg的想法后,比尔盖茨答应给他一个宽松的环境,既领导Visual J++小组,并提供薪水和红利奖金300万美元。这样Borland这个大牛孵化器为微软输送了一位超级大牛。好景不长,SUN公司认为微软破坏了java的跨平台性,很快微软就会利用它的VJ++将java开发人员拉拢到它的周围,而它的VJ++以及WFC的很多特性明显是为了Windows平台设计。SUN中止了对微软的java授权。此后微软便选择Anders Hejlsberg担任C#的首席设计师。

delphi 自定义消息

尽管俺还不是什么开发人员,只能算一个Delphi爱好者,但也可以看看大师们的名著,受点熏陶,
自定义消息:
const
MyMessage=WM_USER + 100;
….
消息处理:
var
MyMessage:TMessage;
with MyMessage do
begin
Message:=MyMessage;
wParam:=0;
lParam:=0;
result:=0;
Panel1.Broadcast(MyMessage);
….
事件过程:
procedure doMyMessage(var msg:TMessage);message;MyMessage;
begin
showMessage(‘这是我的消息’);
end;