Delphi基础回调函数消息及其使用 (2)

上传人:平*** 文档编号:13300575 上传时间:2017-10-23 格式:DOC 页数:34 大小:202.27KB
返回 下载 相关 举报
Delphi基础回调函数消息及其使用 (2)_第1页
第1页 / 共34页
Delphi基础回调函数消息及其使用 (2)_第2页
第2页 / 共34页
Delphi基础回调函数消息及其使用 (2)_第3页
第3页 / 共34页
Delphi基础回调函数消息及其使用 (2)_第4页
第4页 / 共34页
Delphi基础回调函数消息及其使用 (2)_第5页
第5页 / 共34页
点击查看更多>>
资源描述

《Delphi基础回调函数消息及其使用 (2)》由会员分享,可在线阅读,更多相关《Delphi基础回调函数消息及其使用 (2)(34页珍藏版)》请在金锄头文库上搜索。

1、Delphi 基础:回调函数及其使用1 回调函数的概述 回调函数是这样一种机制:调用者在初始化一个对象(这里的对象是泛指,包括 OOP 中的对象、全局函数等)时,将一些参数传递给对象,同时将一个调用者可以访问的函数地址传递给该对象。这个函数就是调用者和被调用者之间的一种通知约定,当约定的事件发生时,被调用者(一般会包含一个工作线程)就会按照回调函数地址调用该函数。 这种方式,调用者在一个线程,被调用者在另一个线程。 消息: 消息也可以看作是某种形式的回调,因为消息也是在初始化时由调用者向被调用者传递一个句柄和一个消息编号,在约定的事件发生时被调用者向调用者发送消息。 这种方式,调用者在主线程中

2、,被调用者在主线程或者工作线程中。 Delphi 事件模型: 在 Delphi 的 VCL 中有很多可视化组件都是使用事件模型,例如 TForm 的 OnCreate 事件,其原理是:在设计时指定事件函数,在运行时事件触发,则会调用在设计时指定的事件函数。 在机制上,Delphi 事件模型与回调是一样的。但具体形式有些区别,纯的回调函数是全局函数的形式,而 Delphi 事件是对象方法的形式,即可以定义如下回调函数类型 type TCallBackFunc = procedure (pData: Pointer) of object;2 回调函数的使用说明 回调函数主要在两个场合使用,第一个是

3、某些 windows 的 API 要求用回调函数作为其参数地址,另一种是用户在某种特定的场合定义的某个函数需要使用回调函数作为其参数地址,对于用户的定义的函数来说,一般是当调用动态连接库中的函数时使用。 对于使用一个回调函数主要有以下几个步骤: 1、定义一个回调函数类型,跟一般的函数过程的定义并没有什么区别,但其定义必须根据需要满足回调函数的函数要求,唯一的区别在于在函数或过程的定义后面必须声明其为 windows标准调用; 例: type THDFunction= function(I:integer;s:string):integer; stdcall;2、 然后根据此原形定义一个相应的函

4、数或过程,对于这个函数或过程来说名字没有什么要求,对函数其参数的类型和返回值的类型必须和定义的回调函数类型完全一致,对于过程来说,只需要其参数类型一样就可以了。 例:根据上面的函数和过程的原形定义一个相应的函数和一个相应的过程。 函数原形定义: Function HdFunExample(k:integer,sExam:string):integer; stdcall;过程定义: procedure HdProExample(sExam:string);stdcall;3、 在程序中实现此回调函数或着过程;Function HdFunExample(k:integer,sExam:string

5、):integer; stdcall; Begin End; procedure HdProExample(sExam:string);stdcall; begin end;4、 调用过程; 回调函数一般作为系统的某个函数的入口地址; 根据调用函数的原形: 进入讨论组讨论。 假设有如下调用函数:function DyHdFunExample(HdFun:THDFunction;I:integer):boolean;注: 在调用函数中通过对函数指针的处理可以直接调用回调函数(即调用函数中的那个是回调函数类型的参数,直接操作它),使回调函数履行一定的操作。即在调用函数中实现回调函数的功能。 调用:

6、 var I:integer; begin I:=DyHdFunExample(HdFunExample,i); /. End;3 举例说明 示例程序在 H: 回调函数示例 目录下面。 回调函数的使用主要在于 windows 原有的 API 函数,但对于用户的自定义的调用函数一般在于动态连接库中。常规的同一个工程下面一般不需要使用回调函数。(个人认为).。Delphi 中的消息处理 Delphi 多线程及消息发送传递结构体参数 1、Unit2:unit Unit2;interfaceuses windows,classes,NMICMP,SysUtils,StdCtrls,messages;c

7、onst WM_MY_PING = WM_USER +1024;type/要传递的消息记录.TPingMsg = recordmsg : array0.1023 of char;id : integer;Handled : boolean;msg2 : string; /建议如果需要动态管理,比如采用 List,采用字符数组的方式会比较好,/因为在动态使用结构时,如过没有处理好,采用 string 就可能会造成内存泄露./当然在这里例子中没关系.end;pPingMsg = TPingMsg;/定义结构体指针.OnPinging = procedure(Context: integer;Msg

8、 : string) of object;ThreadEnd = procedure(Context: integer;Msg:string) of object;TMyPingThread = class(TThread)privateFPingEvent : OnPinging; FEndEvent : ThreadEnd;FMsg : string;FSequenceID : integer;FWinHandl : Hwnd;procedure OnPing(Sender: TObject; Host: String; Size, Time: Integer);procedure Han

9、dlingEnd;procedure HandlingPing;protectedprocedure Execute;override;procedure DoTerminate;override;public/采用函数指针的方式,因为传递过来如果是 UI 控件类的方法,该方法需要访问 UI 元素,则需要做同步处理,/否则可能会导致错误.constructor Create(WinHandl : Hwnd; SequenceID : integer;OutPut: OnPinging;EndEvent: ThreadEnd);overload;end;implementation TMyPin

10、gThread constructor TMyPingThread.Create(WinHandl : Hwnd;SequenceID : integer;OutPut: OnPinging; EndEvent: ThreadEnd);beginself.FPingEvent := OutPut;self.FEndEvent := EndEvent;FSequenceID := SequenceID;FWinHandl := WinHandl;inherited Create(true);end;procedure TMyPingThread.DoTerminate;begininherite

11、d;Synchronize(HandlingEnd);end;procedure TMyPingThread.HandlingEnd();beginif Assigned(self.FEndEvent) thenself.FEndEvent(FSequenceID,FMsg);end;procedure TMyPingThread.HandlingPing();beginif assigned(self.FPingEvent) thenFPingEvent(FSequenceID,FMsg);end;procedure TMyPingThread.Execute;varPingObj : TN

12、MPing;beginself.FreeOnTerminate := true;PingObj := TNMPing.Create(nil);PingObj.OnPing := OnPing;tryPingObj.Pings := 30;PingObj.Host := ;PingObj.Ping;finallyPingObj.Free;end;end;procedure TMyPingThread.OnPing(Sender: TObject; Host: String; Size,Time: Integer);varpMsg : pPingMsg;Msg : TPingMsg;begin/不

13、能直接定义结构体,因为是局部变量,如果是 PostMessage,不会等待,会释放的./但如果采用如下的 new 方式,程序不会主动释放内存,需要配合 Dispose 方法用.new(pmsg);/这种情况下,消息接收方不一定能获取到正确的值.FMsg := host+:+ inttostr(size)+:+inttostr(Time);strcopy(pmsg.msg),pchar(FMsg);pmsg.id := self.FSequenceID;pmsg.Handled := false;pmsg.msg2 := FMsg+xxx;/注意,这里增加字符,并不能增加 sizeof(pmsg

14、)Msg.msg2 := FMsg+xxxx;/注意,这里增加字符,并不能增加 sizeof(Msg)strcopy(Msg.msg),pchar(FMsg);/postmessage(FWinHandl,WM_MY_PING, self.FSequenceID,LPARAM(Msg);/因此我觉得采用 SendMessage 比较好,这样内存的释放可以在这里进行,不会造成内存泄露.Sendmessage(FWinHandl,WM_MY_PING, self.FSequenceID,LPARAM(Msg);/这种方法是让线程等待消息处理,实际上等效于 SendMessage 方法调用. whi

15、le (pmsg.Handled=false) dobeginsleep(10);end;/采用等待方法则在这里释放空间。如果采用消息接收方处理,则这里不需要释放。Dispose(Pmsg);/Synchronize(HandlingPing);end;end.2 form 调用 Unit1unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs,Unit2, StdCtrls;typeTForm1 = class(TForm)Memo1:

16、TMemo;Button1: TButton;Memo2: TMemo;Memo3: TMemo;Memo4: TMemo;procedure Button1Click(Sender: TObject);private Private declarations FThreadCount : integer;procedure HandlingPing(Context:integer;Msg : string);procedure HanglingEnd(Context:integer;Msg : string);procedure OutPut(Context:integer;Msg : string);procedure PingMsgHdl(var Msg:TMessage);message WM_MY_PING;public Public

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号