回调函数的理解及运用

原创 2007年10月10日 21:54:00
首先申明:我是菜鸟,我只不过想把困绕了我很长时间的问题的解决方案发表出来,免得以后我又忘记,同时给还不知道这些小知识的同僚一些帮助。各位不要笑我的浅薄。同时为了表示我的低级,我会很罗嗦的讲一些基本的东西,这些都是我的理解,很不准确。

用我的方法来控制其他程序窗体上的窗口控件,必须先了解什么是回调函数。我的理解是这样的:

回调函数写出来不是自己的程序去调用的,反而是让其他的东西去调用,比如windows操作系统,比如其他的程序等等之类的。但是什么时候被调用却不知道了。回调函数一般是按照调用者的要求定义好参数和返回值的类型,你向调用者提供你的回调函数的入口地址,然后调用者有什么事件发生的时候就可以随时按照你提供的地址调用这个函数通知你,并按照预先规定好的形式传递参数。所以很多人打比方,说回调函数还真有点像您随身带的bp机:告诉别人号码,在它有事情时call您!

所以一个回调函数写出来之后,一定有个注册的动作,就是告诉调用者,你怎么样找到我写的函数。某些windows api 函数会要求以回调函数地址作为其参数之一,例如settimer 、linedda 、enumobjects,以及我们下面要用到的enumwindows。

在delphi里声明一个回调函数的格式很简单,例如:

function enumwindowsproc(ahwnd:longint;lparam:longint):boolean;stdcall;


首先是函数名称可以随便乱取,但函数参数的类型一般不得乱来,其顺序,数据类型等都有规定的,因为这些都是让其他程序调用的,他们已经规定好了的,但参数名称可以随便乱叫。注意后面一定要带上“stdcall”,

stdcall是标准调用,也就是说采用标准windows参数传递方式来调用函数。

编写函数体就很简单了,利用传递过来的参数就可以了,只要记住,这些参数是别人送给你的,你只要知道这些参数代表了什么意思。

再看个向调用者注册回调函数入口地址的函数。
function enumwindows(lpenumfunc: tfnwndenumproc; lparam: lparam): bool; stdcall;


tfnwndenumproc其实就是指针类型。其中的lpenumfunc就是回调函数的入口地址了。

下面是调用enumwindows的格式:
enumwindows(@enumwindowsproc,0);


通过向系统注册回调函数的入口地址,系统就能在需要的时候,调用回调函数,传递参数给它,也许这些参数就是我们想要的。

enumwindows函数的功能是:枚举屏幕上所有程序中的顶层窗口,将窗口句柄以参数的形式传递给回调函数。找到一个窗口,就调用一次回调函数。枚举结束的条件是:要么枚举完所有的窗口,要么回调函数返回false。

lparam: lparam参数是程序定义的值,这个值被传递到回调函数。

回过头来再看一下enumwindowsproc:

function enumwindowsproc(ahwnd:longint;lparam:longint):boolean;stdcall;

当系统找到了一个窗口后,就开始调用这个回调函数,将窗口的句柄作为第一个参数传递过来,将在enumwindows中lparam: lparam这个程序定义的值作为第二个参数传递过来。

所以我们可以在enumwindowsproc函数中利用传递过来的两个参数来做某些处理了。

下面我们新建一个程序列举系统中所有程序的顶层窗口,我们要得到窗口的标题,要得到窗口类名称。

得到窗口标题用:

function getwindowtext(hwnd: hwnd; lpstring: pchar; nmaxcount: integer): integer; stdcall;


该函数功能是将窗口句柄为hwnd的窗口的标题拷入到一个缓冲区lpstring。nmaxcount是拷入缓冲区内的最大的字符数。

要得到窗口标题还可以发送消息:wm_gettext,其实getwindowtext就是发送wm_gettext消息的。

要得到窗口类名称用:

function getclassname(hwnd: hwnd; lpclassname: pchar; nmaxcount: integer): integer; stdcall;


其参数意义和上面的函数差不多。不详细解释了。

我们先编写回调函数:enumwindowsproc。现在告诉自己,我们已经有了两个参数的值了。这两个参数是系统给我们的.

为了显示窗口标题和类名,我们用一个tmemo控件。

先在interface部分声明函数。

function enumwindowsproc(ahwnd:longint;aform:tform1):boolean;stdcall;


注意我将第二个参数改了,不要紧,到时候调用的时候注意看。

然后在implementation部分定义函数:

function enumwindowsproc(ahwnd:longint;aform:tform1):boolean;
var
lpszclassname,lpszwindowtext:array[0..254] of char; //定义两个缓冲区。
begin
getwindowtext(ahwnd,lpszwindowtext,254); //得到窗口标题
getclassname(ahwnd,lpszclassname,254); //得到窗口类名。
aform.memo1.lines.add(strpas(lpszwindowtext));
aform.memo1.lines.add(strpas(lpszclassname));
aform.memo1.lines.add('--------------------');
result:=true;
end;


接着需要做的就是调用enumwindows函数,注册回调函数入口地址,让系统调用回调函数,列举窗口了。所以再添加一个tbutton: btn_listwindow

procedure tform1.btn_listwindowclick(sender: tobject);
begin
enumwindows(@enumwindowsproc,longint(self));
end;


程序清单如下:

unit unit1;

interface

uses
windows, messages, sysutils, variants, classes, graphics, controls, forms,
dialogs, stdctrls;

type
tform1 = class(tform)
memo1: tmemo;
btn_listwindow: tbutton;
procedure btn_listwindowclick(sender: tobject);
private
{ private declarations }
public
{ public declarations }
end;

var
form1: tform1;

function enumwindowsproc(ahwnd:longint;aform:tform1):boolean;stdcall;

implementation
{$r *.dfm}
function enumwindowsproc(ahwnd:longint;aform:tform1):boolean;
var
lpszclassname,lpszwindowtext:array[0..254] of char;
begin
getwindowtext(ahwnd,lpszwindowtext,254);
getclassname(ahwnd,lpszclassname,254);
aform.memo1.lines.add(strpas(lpszwindowtext));
aform.memo1.lines.add(strpas(lpszclassname));
aform.memo1.lines.add('--------------------');
result:=true;
end;

procedure tform1.btn_listwindowclick(sender: tobject);
begin
enumwindows(@enumwindowsproc,longint(self));
end;

end.


f9,运行,看看结果。最好是f7单步跟踪调试一下,看看回调函数是怎么被调用的。
 

回调函数(真好理解)

回调函数   在看LWIP时,见到用回调函数,再看某老外公司OPC源代码时,见到用回调函数。看我国内某些代码(我公司软件等)时没用到。于是,我对回调函数产生了很大的好奇。以前,我写VC程序时用到过...
  • ghevinn
  • ghevinn
  • 2015-06-16 20:09:48
  • 2154

回调函数基本理解

c++ 回调函数机制理解
  • qingtianweichong
  • qingtianweichong
  • 2016-11-05 20:43:26
  • 847

关于回调函数的个人理解

刚入程序员也不是很久,有些东西接触的也不是很多,今天和同事在模块间调用时发现了回调函数,由于之前这方面比较模糊,所以恶补一下并且发一篇个人博客帮助更多的新人理解回调函数。 大家一听到这个名字...
  • tgzjz
  • tgzjz
  • 2015-07-29 18:16:40
  • 940

对Java回调函数的理解

最近在看Java的时候看到了回调函数。只看书写的没有弄明白,于是乎去网上搜了搜相关内容。 首先先看一个比较生动的例子: 某天,我打电话向你请教问题,当然是个难题,^_^,你一时想不出解决方...
  • greyfreedom
  • greyfreedom
  • 2017-03-13 11:13:39
  • 285

Java中对于回调函数的简单理解

有一天,贾君鹏走在路上,突然感觉肚子饿了。于是他给妈妈打电话说:妈妈,饭做好了叫我。然后贾君鹏的妈妈开始做饭,等饭做好了的时候妈妈给贾君鹏回了个电话:快回来吃饭吧,然后贾君鹏就快乐的回家了。 上面就是...
  • u011754975
  • u011754975
  • 2013-09-27 15:59:13
  • 754

js中回调函数的理解 举例说明js回调函数

初学js的时候,被回调函数搞得很晕,现在回过头来总结一下什么是回调函数。   我们先来看看回调的英文定义:A callback is a function that is passed as an ...
  • u012118993
  • u012118993
  • 2017-04-24 10:13:12
  • 612

CC2541之回调函数代码解析

转自:香瓜博客回调函数,解析代码: 一 、定义一个 “ 成员为函数指针 ” 的结构体 1 )定义一个函数指针 /** * Central Event Callback Function */ type...
  • happygrilclh
  • happygrilclh
  • 2017-07-31 20:47:22
  • 239

回调函数理解的整理(某知乎大神写的)

以前看到觉得好,在编译器里写了一遍,这次想找,居然忘了地方,所以还是放这里好 package com.example.callback; public class CallBack...
  • u014001964
  • u014001964
  • 2016-03-02 15:32:43
  • 1441

什么是回调函数?如何运用?

在使用开源项目的时候经常会使用到回调函数,如果把回调函数弄清楚了,那么对我们深入了解开源项目会有很大帮助。 回调函数百度百科的解释: 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)...
  • zhuwentao2150
  • zhuwentao2150
  • 2016-03-29 17:19:36
  • 5865

C++ 对回调函数的理解与运用

函数指针 (1)概念:指针是一个变量,是用来指向内存地址的。一个程序运行时,所有和运行相关的物件都是需要加载到内存中,这就决定了程序运行时的任何物件都可以用指针来指向它。函数是存放在内存代码区域内的...
  • successlzh
  • successlzh
  • 2014-05-04 15:39:34
  • 349
收藏助手
不良信息举报
您举报文章:回调函数的理解及运用
举报原因:
原因补充:

(最多只允许输入30个字)