请大家解释一下Delphi的回调函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请大家解释一下Delphi的回调函数相关的知识,希望对你有一定的参考价值。

如题。

Delphi回调函数及其使用
1 回调函数的概述

回调函数是这样一种机制:调用者在初始化一个对象(这里的对象是泛指,包括OOP中的对象、全局函数等)时,将一些参数传递给对象,同时将一个调用者可以访问的函数地址传递给该对象。这个函数就是调用者和被调用者之间的一种通知约定,当约定的事件发生时,被调用者(一般会包含一个工作线程)就会按照回调函数地址调用该函数。
这种方式,调用者在一个线程,被调用者在另一个线程。

消息:

消息也可以看作是某种形式的回调,因为消息也是在初始化时由调用者向被调用者传递一个句柄和一个消息编号,在约定的事件发生时被调用者向调用者发送消息。
这种方式,调用者在主线程中,被调用者在主线程或者工作线程中。

Delphi事件模型:

在Delphi的VCL中有很多可视化组件都是使用事件模型,例如TForm的OnCreate事件,其原理是:在设计时指定事件函数,在运行时事件触发,则会调用在设计时指定的事件函数。

在机制上,Delphi事件模型与回调是一样的。但具体形式有些区别,纯的回调函数是全局函数的形式,而Delphi事件是对象方法的形式,即可以定义如下回调函数类型
type

TCallBackFunc = procedure (pData: Pointer) of object;

2 回调函数的使用说明

回调函数主要在两个场合使用,第一个是某些Windows的API要求用回调函数作为其参数地址,另一种是用户在某种特定的场合定义的某个函数需要使用回调函数作为其参数地址,对于用户的定义的函数来说,一般是当调用动态连接库中的函数时使用。

对于使用一个回调函数主要有以下几个步骤:

1、定义一个回调函数类型,跟一般的函数过程的定义并没有什么区别,但其定义必须根据需要满足回调函数的函数要求,唯一的区别在于在函数或过程的定义后面必须声明其为windows标准调用;

例:

type

THDFunction= function(I:integer;s:string):integer; stdcall;

对于过程的声明:

type

THDProcedure=procedure(s:string); stdcall;

2、 然后根据此原形定义一个相应的函数或过程,对于这个函数或过程来说名字没有什么要求,对函数其参数的类型和返回值的类型必须和定义的回调函数类型完全一致,对于过程来说,只需要其参数类型一样就可以了。

例:根据上面的函数和过程的原形定义一个相应的函数和一个相应的过程。

函数原形定义:

Function HdFunExample(k:integer,sExam:string):integer; stdcall;

过程定义:

procedure HdProExample(sExam:string);stdcall;

3、 在程序中实现此回调函数或着过程;

Function HdFunExample(k:integer,sExam:string):integer; stdcall;

Begin

End;

procedure HdProExample(sExam:string);stdcall;

begin

end;

4、 调用过程;

回调函数一般作为系统的某个函数的入口地址;

根据调用函数的原形:

假设有如下调用函数:

function DyHdFunExample(HdFun:THDFunction;I:integer):boolean;

注:

在调用函数中通过对函数指针的处理可以直接调用回调函数(即调用函数中的那个是回调函数类型的参数,直接操作它),使回调函数履行一定的操作。即在调用函数中实现回调函数的功能。

调用:

var

I:integer;

begin

I:=DyHdFunExample(@HdFunExample,i);

//…….

End;

3 举例说明

示例程序在H:\ 回调函数示例\ 目录下面。

回调函数的使用主要在于Windows原有的API函数,但对于用户的自定义的调用函数一般在于动态连接库中。常规的同一个工程下面一般不需要使用回调函数。(个人认为).。
参考技术A 你去这个地址看一下:http://www.pconline.com.cn/pcedu/empolder/gj/delphi/10311/242614.html 参考技术B 推荐答案已经很好的,只对最后一句说说咱的认识——“常规的同一个工程下面一般不需要使用回调函数。(个人认为)”

回调函数的作用是接口,为什么用接口呢?原因就是具体想做的事儿或者做事儿的方法太多了,没办法穷举,所以留个口子让编程者自己去发挥。举例说明:
1、EnumWindow要求一个回调函数,是什么目的呢?枚举窗口是个挺复杂的活儿,要是自己动手实现,不但要了解操作系统底层知识,还需要精湛的编程技巧和大量编码,于是操作系统帮你做了这部分最有难度、最繁琐的活儿,它帮你把一个个窗口找到,然后问你,找到了,你想干什么,表达想干什么的程序代码才是你亲自编写的,编写在那个回调函数中。常见的企图是把找到的一个个窗口暂存起来,以备后用,后有何用?向窗口发各种各样的消息均是用法,比如说发关闭消息。哪怕是没有实际的动机,就是想溜溜操作系统,让它跑一圈,把结果告诉咱,咱啥也不干。
2、快速排序要求的回调函数:排序的一个基本操作是判断两个元素谁先谁后,这个逻辑可就多了,对于整数,有从大到小、从小到大,对于字符串,有按照串大小、串长度大小等,不可穷举,完全是用户的自由,提供快排算法的先贤不知道,只能留个口子,让你来实现。先贤的功绩在于把快排这个很复杂的算法框架给你包装好了,让你不需要了解算法细节就能高效地达到意图。举个罕见的例子:有时候我们需要的不是精致的排序结果,而是想要尽可能乱的顺序,对于一个文本文件,手工操作就是反复随便剪切一些行,再粘贴到随便的位置,编程实现怎么做呢?可以用快速排序,比较大小的回调函数返回随机正负数即可,结果就是一个字:乱;两个字就是:胡乱;四个字就是:乱七八糟。

以上两个例子,尤其是排序的例子,都有可能是同一个工程下需要的,所以说,回调函数的本质是接口,而不是用在哪里。

谁能通俗的解释回调函数?

我实在不理解为什么要回调,怎么回调,怎么执行过程.跪求高手前辈指点啊,或者有什么这方面的书籍可以推荐的,请赐教.分我不在乎,问题能解决我必有回报!先谢过了
我还是不明白,这与直接调用另外一个函数有什么区别,为什么非得"回调",
假设,A函数调用了一个回调函数B,,然后等B执行完了再反过来调用A.
这样还不如在A函数里直接调用B函数呢,呵呵,晚辈一时心急,请各位不惜赐教,分是无所谓的

我又有另外一个疑问了,如果说"A:"B,你去干f。干好了叫我干g。"",那为什么非得把函数用地址传进去呢?直接在f函数里调用不就OK了么,何必要绕个弯子

多谢" BlueWanderer"前辈的指点,这样吧,如果你能给我 推荐些关于这类似的问题的书,我就再给你加50分.如何?

前辈,那有没有书能详细的介绍windows消息机制之类的比较好的书 呢

callback这个词本意是打电话对方不在,通过某种方法让那个人在的时候给你打回来。

void f() ... 调用这个函数话...和回调没有任何关系。就相当于A:"B,你去干f。"

void f(int (*g)()) ... g(); 这个函数就带有回调的特征。调用的时候好像 A:"B,你去干f。干好了叫我干g。"

也就是调用方留一个让被调用方在特定时候通知他的线索,对他进行“回调”。

----

接着上面说,f这个工作要求是干完以后干一件事g。但是这个g并不是f自己规定的,是在调用f的时候再告诉f的。比如你可以让B在完成的时候,什么也不干;或者叫你一声;或者让你干另外一件事。就是说g这个工作本身就是个变量。

----

如果不作为参数提供,g就成了f固定的一部分。A直接说“你去干f”不就是了。作为参数的意义就在于,这个g可以随意改变。

----

基本上不可能有书会去具体讲回调函数。回调只是一个很基本的函数指针的使用。
参考技术A 什么是回调函数?
首先做一个形象的比喻:
你有一个任务,但是有一部分你不会做,或者说不愿做,所以我来帮你做这部分,你做你其它的任务工作或者等着我的消息,但是当我完成的时候我要通知你我做好了,你可以用了,我怎么通知你呢?你给我一部手机,让我做完后给你打电话,我就打给你了,你拿到我的成果加到你的工作中,继续完成其它的工作.这就叫回叫,手机是我通知你的手段,它就是回叫函数,也叫回调函数
回调函数是应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理异步事件。应用程序把回调函数的地址指针告诉DLL,而DLL在适当的时候会调用该函数。回调函数必须遵守事先规定好的参数格式和传递方式,否则DLL一调用它就会引起程序或系统的崩溃。通常情况下,回调函数采用标准WindowsAPI的调用方式,即__stdcall,当然,DLL编制者可以自己定义调用方式,但客户程序也必须遵守相同的规定。在__stdcall方式下,函数的参数按从右到左的顺序压入堆栈,除了明确指明是指针或引用外,参数都按值传递,函数返回之前自己负责把参数从堆栈中弹出。
理解回调函数!
程序在调用一个函数(function)时(通常指api).相当于程序(program)呼叫(Call)了一个函数(function)关系表示如下:
call(调用)
program --------------------→ dll
程序在调用一个函数时,将自己的函数的地址作为参数传递给程序调用的函数时(那么这个自己的函数称回调函数).需要回调函数的 DLL 函数往往是一些必须重复执行某些操作的函数.关系表示如下:
call(调用)
program --------------------→ dll
↑ ¦
¦_______________________________¦
callback(回调)
当你调用的函数在传递返回值给回调函数时,你就可以利用回调函数来处理或完成一定的操作。至于如何定义自己的回调函数,跟具体使用的API函数有关,很多不同类别的回调函数有各种各样的参数,有关这些参数的描述一般在帮助中有说明回调函数的参数和返回值等.其实简单说回调函数就是你所写的函数满足一定条件后,被DLL调用!
也有这样的说法(比较容易理解):
回调函数就好像是一个中断处理函数,系统在符合你设定的条件时自动调用。为此,你需要做三件事:
1. 声明;
2. 定义;
3. 设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于DLL调用。
.NET Framework 开发人员指南
回调函数是托管应用程序中可帮助非托管 DLL 函数完成任务的代码。对回调函数的调用将从托管应用程序中,通过一个 DLL 函数,间接地传递给托管实现。在用平台调用调用的多种 DLL 函数中,有些函数要求正确地运行托管代码中的回调函数。
回调函数和实现要从托管代码中调用大多数 DLL 函数,可创建该函数的托管定义,然后调用该函数。此过程比较直接。
要使用需要回调函数的 DLL 函数,则会有一些附加的步骤。首先,必须在文档中查阅该函数,确定该函数是否需要回调。接着,必须在托管应用程序中创建回调函数。最后,调用该 DLL 函数,并将指向回调函数的指针当作参数进行传递。右图总结了这些步骤。
回调函数非常适合在重复执行任务的情况下使用。另一个常见用途是与枚举函数(如 Win32 API 中的 EnumFontFamilies、EnumPrinters 和 EnumWindows)一起使用。EnumWindows 函数枚举计算机上的所有现有窗口,并调用回调函数以针对每个窗口执行任务.
参考技术B 简单的说,回调函数,当你调用了一个函数,但是这个函数仅仅是算法的一部分,你还需要自己定义一部分算法,该函数会自动调用你自定义的“回调函数”。

如下例子:

比如你要枚举所有的窗口。可以调用EnumWindows函数。但是,EnumWindows仅仅是将窗口枚举出来,至于如何处理则需要你来定义。

就是说,当你调用EnumWindow,要指定一个回调函数,来告诉EnumWindow,当她枚举到窗口的时候,应该怎么处理这个窗口。

CallBack( HWND wnd ... ) //EnumWindow的回调函数

//这里是自定定义的
//假设设计目的是要找出标题为 “xxx”的窗口;
CString str = GetWindowText( wnd );
if( ! str.Compare( "xxx" ))

g_hWnd = wnd; // 保存这个窗口的句柄;
return TRUE; // 告诉EnumWindow不需要再继续枚举了。

else
return FALSE; // 告诉EnumWindow,这次枚举到的
// 不是我要找的,还需要继续枚举下一个窗口。


............某代码.............
g_hWnd = NULL; // 初始化保存所找窗口句柄的变量。
EnumWindow( CallBack ...... ); 调用枚举函数并指定回调函数。
if( g_hWnd )
// 说明已经找到了
else
// 依然没有找到。

百度上贴代码,真是影像美感啊。
参考技术C 老板分配给你一个任务,但考虑到你完成这个任务存在困难。于是老板告诉你:如有任何问题,请于x时x地将你不能完成的任务提交给我,我帮你完成。然后老板把你提交的东西带走并帮你实现。

回调函数作用与此类似。一个服务系统(包括windows,以及在dll开发中,我们称之为服务程序),需要调用很多函数或接受许多未知信息来运行,这时,我们可以提供个回调函数接口给用户,由用户去实现这个函数。注意,回调函数不用我们去调用,是由服务系统调用的,我们的任务是去实现回调函数,这样我们就完成了与服务程序的对话。

回调函数不是由你调用的,是系统提供给你让你去实现、去使用的。回调函数是被哪里调用的,在什么情况下调用的,你是不知道的,你只能实现这个函数,只要你实现了这个函数,你的程序就会使用到这个函数,而普通函数你的程序中如果不调用则不起作用。例如窗口过程函数,你的程序并不调用,但你需要实现这个函数,这样你的程序执行后,窗口过程函数就会起作用;如果你定义了一个普通函数fun,如果你的程序中并没有调用,那么在你的程序中fun这个函数就不会起作用。
参考技术D 回调只是名称上的东西.CALL BACK宏其实就是stdcall.
回调就是你把A函数的地址传给B函数.B函数在一定条件满足后执行A函数.
任何函数都可以作为回调函数.
没有很深的技术上的知识.

以上是关于请大家解释一下Delphi的回调函数的主要内容,如果未能解决你的问题,请参考以下文章

Delphi回调函数及其使用

DELPHI调用DLL时的回调函数问题

谁能通俗的解释回调函数?

delphi回调函数

Delphi 回调函数及property的使用

Delphi DLL 和 Delphi EXE 之间的回调功能