C++中DLL函数的导出和导入

C++中DLL函数的导出和导入
C++中DLL函数的导出和导入

回调函数

对于很多初学者来说,往往觉得回调函数很神秘,很想知道回调函数的工作原理。本文将要解释什么是回调函数、它们有什么好处、为什么要使用它们等等问题,在开始之前,假设你已经熟知了函数指针。 什么是回调函数? 简而言之,回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。 为什么要使用回调函数? 因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。 如果想知道回调函数在实际中有什么作用,先假设有这样一种情况,我们要编写一个库,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排序、shake排序等等,但为使库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,想让库可用于多种数据类型(int、float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。 回调可用于通知机制,例如,有时要在程序中设置一个计时器,每到一定时间,程序会得到相应的通知,但通知机制的实现者对我们的程序一无所知。而此时,就需有一个特定原型的函数指针,用这个指针来进行回调,来通知我们的程序事件已经发生。实际上,SetTimer() API使用了一个回调函数来通知计时器,而且,万一没有提供回调函数,它还会把一个消息发往程序的消息队列。 另一个使用回调机制的API函数是EnumWindow(),它枚举屏幕上所有的顶层窗口,为每个窗口调用一个程序提供的函数,并传递窗口的处理程序。如果被调用者返回一个值,就继续进行迭代,否则,退出。EnumWindow()并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为基于返回值,它将继续执行或退出。 不管怎么说,回调函数是继续自C语言的,因而,在C++中,应只在与C代码建立接口,或与已有的回调接口打交道时,才使用回调函数。除了上述情况,在C++中应使用虚拟方法或函数符(functor),而不是回调函数。 一个简单的回调函数实现 下面创建了一个sort.dll的动态链接库,它导出了一个名为CompareFunction的类型--typedef int (__stdcall *CompareFunction)(const byte*, const byte*),它就是回调函数的类型。另外,它也导出了两个方法:Bubblesort()和Quicksort(),这两个方法原型相同,但实现了不同的排序算法。

回调函数与回调机制

回调函数与回调机制 1. 什么是回调函数 回调函数(callback Function),顾名思义,用于回调的函数。回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数。回调函数是一个工作流的一部分,由工作流来决定函数的调用(回调)时机。回调函数包含下面几个特性: ?属于工作流的一个部分; ?必须按照工作流指定的调用约定来申明(定义); ?他的调用时机由工作流决定,回调函数的实现者不能直接调用回调函数来实现工作流的功能; 2. 回调机制 回调机制是一种常见的设计模型,他把工作流内的某个功能,按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。 如上图所示,工作流提供了两个对外接口(获取参数、显示结果),以回调函数的形式实现。 ?“获取参数”回调函数,需要工作流使用者设定工作流计算需要的参数。 ?“显示结果”回调函数,提供计算结果给工作流使用者。

再以Windows的枚举顶级窗体为例。函数EnumWindows用于枚举当前系统中的所有顶级窗口,其函数原型为: BOOL EnumWindows( WNDENUMPROC lpEnumFunc, // callback function LPARAM lParam // application-defined value ); 其中lpEnumFunc是一个回调函数,他用于返回枚举过程中的获得的窗口的句柄。其定义约定为: BOOL CALLBACK EnumWindowsProc( HWND hwnd, // handle to parent window LPARAM lParam // application-defined value ); 在这个例子中,EnumWindows 是一个工作流,这个工作流用于遍历windows的所有窗口并获得其句柄。用户使用EnumWindows工作流的目的是想通过工作流来来获取窗口的句柄以便针对特定的一个或多个窗口进行相关处理。于是EnumWindows就扩展出接口lpEnumFunc,用于返回遍历的窗口句柄。 EnumWindows工作流的结束有两个方式:1,用户在回调函数中返回FALSE;2,再也找不到顶级窗口。我们可以推测EnumWindows的实现机制如下: 注:下列代码中的FindFirstTopWindows(), FindNextTopWindow()为假设的,Windows API 没有此函数,只是为了表明Enumwindows的内部流程。 BOOL EnumWindows( WNDENUMPROC lpEnumFunc, // callback function LPARAM lParam // application-defined value ) { BOOL bRet = TRUE; HWND hWnd = ::FindFirstTopWindows(); // 此函数是假设的,查找第一个顶级窗口 // 当hWnd为0时表示再也找不到顶级窗口 while( hWnd ) { bRet = (*lpEnumFunc)( hWnd, value ); if( !bRet) break; // 终止EnumWindows工作流; hWnd = ::FindNextWindow(); // 此函数是假设的,查找下一个顶级窗口 } } 在EnumWindows(...)函数中,实现了窗口枚举的工作流,他通过回调机制把用户关心(顶级窗口句柄)的和枚举工作流分开,用户不需要知道EnumWindows的具体实现,用户只要知道,设定了lpEnumFunc函数,然后把函数指针传给EnumWindwos就可以获得想要的窗口句柄。

C++中DLL函数的导出和导入

1.使用DEF 文件从DLL 导出 模块定义(.def) 文件是包含一个或多个描述DLL 各种属性的Module 语句的文本文件。如果不使用__declspec(dllexport)关键字导出DLL 的函数,则DLL 需要 .def 文件。 .def 文件必须至少包含下列模块定义语句: 文件中的第一个语句必须是LIBRARY 语句。此语句将 .def 文件标识为属于DLL。LIBRARY 语句的后面是DLL 的名称。链接器将此名称放到DLL 的导入库中。 EXPORTS 语句列出名称,可能的话还会列出DLL 导出函数的序号值。通过在函数名的后面加上@ 符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从1 到N,其中N 是DLL 导出函数的个数。如果希望按序号导出函数,请参见按序号而不是按名称从DLL 导出函数以及本主题。 例如,包含实现二进制搜索树的代码的DLL 看上去可能像下面这样: LIBRARY BTREE EXPORTS Insert @1 Delete @2 Member @3 Min @4 如果使用MFC DLL 向导创建MFC DLL,则向导将为您创建主干 .def 文件并将其自动添加到项目中。添加要导出到此文件的函数名。对于非MFC DLL,必须亲自创建 .def 文件并将其添加到项目中。 如果导出C++ 文件中的函数,必须将修饰名放到 .def 文件中,或者通过使用外部“C”定义具有标准C 链接的导出函数。如果需要将修饰名放到 .def

文件中,则可以通过使用DUMPBIN 工具或/MAP 链接器选项来获取修饰名。请注意,编译器产生的修饰名是编译器特定的。如果将Visual C++ 编译器产生的修饰名放到 .def 文件中,则链接到DLL 的应用程序必须也是用相同版本的Visual C++ 生成的,这样调用应用程序中的修饰名才能与DLL 的 .def 文件中的导出名相匹配。 如果生成扩展DLL 并使用 .def 文件导出,则将下列代码放在包含导出类的头文件的开头和结尾: #undef AFX_DATA #define AFX_DATA AFX_EXT_DATA // #undef AFX_DATA #define AFX_DATA 这些代码行确保内部使用的MFC 变量或添加到类的变量是从扩展DLL 导出(或导入)的。例如,当使用DECLARE_DYNAMIC派生类时,该宏扩展以将CRuntimeClass成员变量添加到类。省去这四行代码可能会导致不能正确编译或链接DLL,或在客户端应用程序链接到DLL 时导致错误。 当生成DLL 时,链接器使用 .def 文件创建导出(.exp) 文件和导入库(.lib) 文件。然后,链接器使用导出文件生成DLL 文件。隐式链接到DLL 的可执行文件在生成时链接到导入库。 请注意,MFC 本身使用 .def 文件从MFCx0.dll 导出函数和类。 2.使用_declspec(dllexport) 从DLL 导出 Microsoft 在Visual C++ 的16 位编译器版本中引入了_export,使编译器得以自动生成导出名并将它们放到一个 .lib 文件中。然后,此 .lib 文件就可以像静态 .lib 那样用于与DLL 链接。

关于回调函数的几个例子(c)

以下是一个简单的例子。实现了一个repeat_three_times函数,可以把调用者传来的任何回调函数连续执行三次。 例 1. 回调函数 /* para_callback.h */ #ifndef PARA_CALLBACK_H #define PARA_CALLBACK_H typedef void (*callback_t)(void *); extern void repeat_three_times(callback_t, void *); #endif /* para_callback.c */ #include "para_callback.h" void repeat_three_times(callback_t f, void *para) { f(para); f(para); f(para); } /* main.c */ #include #include "para_callback.h" void say_hello(void *str) { printf("Hello %s\n", (const char *)str); } void count_numbers(void *num) { int i; for(i=1; i<=(int)num; i++) printf("%d ", i); putchar('\n');

} int main(void) { repeat_three_times(say_hello, "Guys"); repeat_three_times(count_numbers, (void *)4); return 0; } 回顾一下前面几节的例子,参数类型都是由实现者规定的。而本例中回调函数的参数按什么类型解释由调用者规定,对于实现者来说就是一个void *指针,实现者只负责将这个指针转交给回调函数,而不关心它到底指向什么数据类型。调用者知道自己传的参数是char *型的,那么在自己提供的回调函数中就应该知道参数要转换成char *型来解释。 回调函数的一个典型应用就是实现类似C++的泛型算法(Generics Algorithm)。下面实现的max函数可以在任意一组对象中找出最大值,可以是一组int、一组char或者一组结构体,但是实现者并不知道怎样去比较两个对象的大小,调用者需要提供一个做比较操作的回调函数。 例 2. 泛型算法 /* generics.h */ #ifndef GENERICS_H #define GENERICS_H typedef int (*cmp_t)(void *, void *); extern void *max(void *data[], int num, cmp_t cmp); #endif /* generics.c */ #include "generics.h" void *max(void *data[], int num, cmp_t cmp) { int i; void *temp = data[0];

回调函数的概念及其使用

回调函数的概念及其使用

回调函数的概念及其使用 1 什么是回调 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础,因此,下面我们着重讨论回调机制在不同软件架构中的实现。 对于不同类型的语言(如结构化语言和对象语言)、平台(Win32、JDK)或构架(CORBA、DCOM、WebService),客户和服务的交互除了同步方式以外,都需要具备一定的异步通知机制,让服务方(或接口提供方)在某些情况下能够主动通知客户,而回调是实现异步的一个最简捷的途径。 对于一般的结构化语言,可以通过回调函数来实现回调。回调函数也是一个函数或过程,不过它是一个由调用方自己实现,供被调用方使用的特殊函数。

在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类成为回调类,回调类的对象成为回调对象。对于象C++或Object Pascal 这些兼容了过程特性的对象语言,不仅提供了回调对象、回调方法等特性,也能兼容过程语言的回调函数机制。 Windows平台的消息机制也可以看作是回调的一种应用,我们通过系统提供的接口注册消息处理函数(即回调函数),从而实现接收、处理消息的目的。由于Windows平台的API是用C语言来构建的,我们可以认为它也是回调函数的一个特例。 对于分布式组件代理体系CORBA,异步处理有多种方式,如回调、事件服务、通知服务等。事件服务和通知服务是CORBA用来处理异步消息的标准服务,他们主要负责消息的处理、派发、维护等工作。对一些简单的异步处理过程,我们可以通过回调机制来实现。 下面我们集中比较具有代表性的语言(C、Object Pascal)和架构(CORBA)来分析回调的实现方式、具体作用等。 2 过程语言中的回调(C) 2.1 函数指针 回调在C语言中是通过函数指针来实现的,通过将回调函数的地址传给被调函数从而实现回调。因此,要实现回调,必须首先定义函数指针,请看下面的例子: void Func(char *s);// 函数原型 void (*pFunc) (char *);//函数指针 可以看出,函数的定义和函数指针的定义非常类似。 一般的化,为了简化函数指针类型的变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。 typedef void(*pcb)(char *); 回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。 被调函数的例子:

VB如何调用dll函数

VB如何调用dll函数 2008-01-10 17:17 開始習慣孤單 | 分类:VB| 浏览13089次 假如我有个DLL,名为 asdfg.dll 它里面有一个函数 zxc(参数1,参数2) 我要用这个函数,该怎么写? 请高手帮我写出脚本,有时间的话请再加上注释 谢谢!! 2008-01-10 19:50 提问者采纳 1.在工程-引用中将asdfg.dll引用过来 2.dim AAA as asdfg 'asdfg是类模块的名称 Private Sub Form_Load() dim x Set AAA = New asdfg x = AAA.zxc(参数1,参数2)'参数1,2自己写 End Sub 建议你了解一下下面dll的制作方法,理解就更透彻了。下面内容来自百度。 1.新建一个ActiveX Dll,工程名字为vbmytestdll,类模块

名字为mytestdll 2.类模块内容只有一个函数,主要返回DLL的HELLO WORLD Public Function dlltest1() As String dlltest1 = "HELLO WORLD" End Function 3.保存,生成DLL,名字为 vbmytestdll.dll 4.新建一个EXE工程,在菜单: 工程---引用---浏览里找到vbmytestdll.dll,把它引用进来 5.EXE工程代码如下: Option Explicit Dim testdll As mytestdll'类模块名字 Private Sub Form_Load() Set testdll = New mytestdll 'DLL的一个新实例 Me.Caption = testdll.dlltest1 '我的标题=返回DLL的HELLO WORLD

回调函数实现dll向主程序传递数据

回调函数实现dll向主程序传递数据 用dll封装窗口主要是封装对话框。软件开发中经常要使用的一个功能是导入数据,且要求可视化操作,如为对应的变量选择对应的列,设置数据的起始和终止行等。希望将界面做成如下形式: 由于这个界面和数据导入的通用性,我们希望将其封装到dll,提供一些接口进行窗口显示和数据传递就可以了。但是我们遇到一个问题:这里的数据传递我们希望是在点击OK之后获取对话框也就是dll中的数据传递到主程序,而在主程序中我们装载dll的函数是一个顺序的执行过程,不能进行消息响应。因此我们想到了使用回调函数。在这里的具体思想就是:在点dll的时候,我们使用回调函数将数据传到主程序,调用主程序的函数进行处理。虽然这样的过程有些打乱程序的执行顺序,但是可以到达我们的目的。下面介绍实现过程: 1、我们建立一个MFC的规则dll将写好的导入数据的对话框代码进行复制, 封装dll。 2、除了导出读取数据和显示对话框的函数之外,导出一个传递函数(回调 函数)形参的函数,这里我们采用一个在一个h文件中定义导出函数, 并利用宏切换功能,实现dll和主程序包含同一个h文件就可以实现函数 的导出和导入。具体代码见程序实例中的DllExport.h 3、具体介绍使用回调函数传递数据功能的实现。在DllExport.h中声明一个 函数的指针 typedef void (* pFunc)(double **pdata,int* nConut); 其中的两个参数pdata和nCount分别为我们要传递数据(一个二维数组)的指针,和一共有多少行数据。 接着声明一个以这个函数指针为形参的导出函数:

直调、回调、异调

1. 什么是回调函数 回调函数(callback Function),顾名思义,用于回调的函数。回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数。回调函数是一个工作流的一部分,由工作流来决定函数的调用(回调)时机。回调函数包含下面几个特性: 1、属于工作流的一个部分; 2、必须按照工作流指定的调用约定来申明(定义); 3、他的调用时机由工作流决定,回调函数的实现者不能直接调用回调函数来实现工作流的功能; 2. 回调机制 回调机制是一种常见的设计模型,他把工作流内的某个功能,按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。 ======================================================= java回调机制: 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。 同步调用:一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用; 回调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口; 异步调用:一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。 回调和异步调用的关系非常紧密:使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。 ======================================================== 用Java里的例子: package callbackexample; public interface ICallBack { //需要回调的方法public void postExec(); } 另外的一个类: package callbackexample; public class FooBar { //组合聚合原则 private ICallBack callBack; public void setCallBack(ICallBack callBack) { this.callBack = callBack; doSth(); } public void doSth() { callBack.postExec(); } } 第二个类在测试类里面,是一个匿名类: package callbackexample; public class Test { public static void main(String[] args) { FooBar foo = new FooBar(); foo.setCallBack(new

labview的深入探索----labview与回调函数

labview的深入探索----labview与回调函数 回调函数是WINDOWS 编程(API 编程)的核心内容之一,在许多高级编程语 言,如VB,VC(MFC)中已经封装了回调函数,取而代之的是事件响应函数,但是,追 溯其本质,实际就是回调函数.所谓WINDOWS 回调函数,就是按照WINDOWS 的规范,编写的(CALLBACK)函数,当WINDOWS 检测到事件发生时,自动调用的 函数,WINDOWS 是通过函数指针调用的,因此,回调函数的内容是由用户决定的, 而何时调用是由操作系统决定的.我们看一下CVI 中的一般回调函数的定义int callback aaaa(int panel,int control,int event1,int event2,callbackdata *data);回调函数的参数是有操作系统提供的,比如上面的回调函数,panel---表示的哪个面板(窗口) 发生的事件control---表示的面板上哪个控件发生的事件event1 event2 表示事件 的类型和相应数据,比如鼠标坐标等回调函数是一般高级编程语言的基本功能, 但是,在LABVIEW8.X 之前是不支持的,这极大限制了LABVIEW 功能的扩展, 因为ACTIVEX,.NET 都需要回调函数.8.X 中,增加了回调函数的功能,主要用于ACTIVE,.NET 和LABVIEW 自身控件,LABVIEW 例子程序中提供了几个例子, 是有关ACTIVEX 和.NET 调用的,下面,我们通过LABVIEW 自身控件说明一下 回调函数的使用方法.在.NET 摸板中也提供了这个节点,从分类上就可以看出,注 册回调函数主要是用于ACTIVEX 和.NET 的.下面我们做一个简单的回调函数 的程序,有两个功能,返回当前值的变化和记录控件被点击的次数注册回调函数 需要三个参数:控件参考,用户参数和自动生成的回调函数,有了控件参考,我们就 可以选择事件的类型,用户参数主要是用于返回结果,因为回调函数是由操作系 统调用的,没有办法通过数据流返回处理结果.添加了这两个参数后,就可以自动 生成回调函数了回调函数如下图所示简单编程,CONTROL 的值传递给 INDICATOR 这样值变化的回调函数完成了,下面我们通过鼠标UP 事件来记录

在VB中调用DLL的方法

1制作好DLL之后,就可以用VB调用它,实现VB调用C程序。VB程序要使用DLL中的函数,首先必须要有特殊的声明,用Declare声明语句在窗体级或模块级或全局模块的代码声明段进行声明,将动态链接库中的函数声明到VB中,供VB程序调用。 语句格式为:Declare Sub过程名Lib[Alias"别名]([ByVal参数AS类型]),或为Declare Function函数名Lib[Alias"别名]([ByVal参数AS类型])AS类型在声明中首先用Declare 关键字表示声明DLL中的函数。在C语言中有的函数类型为VOID,它表示不具有返回值,则必须用关键字Sub将其声明成过程。有的函数具有返回值,则必须用关键字Function将其声明成函数,并且在声明语句的最后要用AS关键字指明函数返回值的类型。 例如上面的ADD.DLL在VB中就可以声明为: Declare Function ADD Lib“c:\ADD.dll”(ByVal X AS Integer,ByVal Y AS Integer,ByVal filein asstring)AS Integer 通过此声明语句将函数ADD声明到VB中,便可直接调用。 2、dll文件中的函数好像是C语言写的, //函数名:int__stdcall GetMacNo(int*MacNo) //功能:获取卡机的卡机号(单机时) //参数:MacNo[0]-被读出的卡机号 //返回值:0-成功, //2-PC接收超时, //3-应答错误 dll的文件名是COMM232.dll 函数的形参int*MacNo是指针吗? 在VB中应该怎么声明和调用该函数? VB里也可以定义指针吗? 问题补充:vb调用dll文件中的函数我是会的,但这儿的形参有一个星号才不知是怎么一回事, 我是这样声明的对吗? Public Declare Function GetMacNo Lib"COMM232.dll"(ByVal MacNo As Integer)As Integer 又应该怎么调用呢?要先定义一个指针的变量再传给*MacNo还是要怎么做? 都说了MacNo是被读出的卡机号,那么就是传址的了。 dim l as integer dim m as integer l=GetMacNo(m) if l=0then label1.caption="卡机号:"&m elseif l=2then msgbox"PC接收超时" elseif l=3then msgbox"应答错误" end if

易语言中调用DLL使用说明

易语言中调用DLL使用说明 基本说明 本文所描述的部分功能需易语言4.01或以上版本支持。 “在易语言中调用DLL”包含两方面的内容:调用Windows系统API函数;调用普通DLL函数。 下文用到的“调用API”或“调用DLL”等字眼,除非特别注明,一般都是指以上两方面之一或之和,视上下文而定。绝大多数情况下,无需明确区分调用的是系统API还是普通DLL。 目前易语言只支持以stdcall方式调用DLL中的导出函数。 Windows系统API一般都是以stdcall调用方式导出的,故在易语言中调用它们时通常不必考虑函数调用方式的问题。而普通DLL有可能导出“非stdcall调用方式”(比如cdecl)的函数,调用时需要特别注意。一般而言,考虑到通用性,DLL开发者都会选择导出以sdtcall方式调用的函数。(支持生成DLL的编程语言通常都支持导出stdcall调用方式的函数,具体实现请参考各编程语言手册。) 易语言编译生成的DLL,其导出函数全部为stdcall调用方式,所以在易语言中调用易语言生成的DLL不存在问题。 目前在易语言中调用DLL时只支持1字节对齐的结构(自定义数据类型) 如果DLL命令的某个参数或参数的某个成员是结构类型(自定义数据类型),则其对齐方式必须是1字节对齐。Windows系统API中所用到的结构都是1字节对齐的,故在调用API时不受此限制。但如果想用其它编程语言生成DLL供易语言调用且数据类型中包含了1或2字节数据长度的成员(如字符型或短整数),就需要考虑结构的1字节对齐。 在VC中,可以这样定义1字节对齐的结构(结构在C/C++中称为struct):

Java 异步回调机制实例解析

Java 异步回调机制实例解析 回调,回调。要先有调用,才有调用者和被调用者之间的回调。下面给大家介绍Java异步回调机制实例解析,欢迎阅读! 一、什么是回调 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。 回调是一种特殊的调用,至于三种方式也有点不同。 1、同步回调,即阻塞,单向。 2、回调,即双向(类似自行车的两个齿轮)。 3、异步调用,即通过异步消息进行通知。 二、CS中的异步回调(java案例) 比如这里模拟个场景:客户端发送msg给服务端,服务端处理后(5秒),回调给客户端,告知处理成功。代码如下: 回调接口类: /** *@authorJeffLee *@sincexx-10-2121:34:21 *回调模式-回调接口类 */ publicinterfaceCSCallBack{ publicvoidprocess(Stringstatus); }

模拟客户端: /** *@authorJeffLee *@sincexx-10-2121:25:14 *回调模式-模拟客户端类 */ publicclassClientimplementsCSCallBack{ privateServerserver; publicClient(Serverserver){ this.server=server; } publicvoidsendMsg(finalStringmsg){ System.out.println("客户端:发送的消息为:"+msg); newThread(newRunnable(){ @Override publicvoidrun(){ server.getClientMsg(Client.this,msg); } }).start(); System.out.println("客户端:异步发送成功"); } @Override

delphi之调用外部dll中的函数

分早绑定和晚绑定两种。 早绑定的代码如下: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; //MB 函数的声明: function MB(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; implementation {$R *.dfm} {调用外部 DLL 中的函数,譬如调用系统 user32.dll 中的 MessageBoxA} //function MB(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; // stdcall; external user32 name 'MessageBoxA'; {其中 user32 是 Delphi 定义的常量 'user32.dll',可以直接写成:} //function MB(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; // stdcall; external 'user32.dll' name 'MessageBoxA'; {name 后面说明函数的真实名字} {external 子句说明单元载入时就加载函数,也就是早绑定;如果晚绑定需要用LoadLibrary} {stdcall 指令表示参数传递是从右到左(Pascal则反之),不通过CPU寄存器

C语言回调函数讲解

回调函数 一、什么是回调函数? 回调函数就是函数指针的一种用法! 使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。 二、回调函数怎么开发?怎么使用? 回调函数是一个程序员不能显式调用的函数,要想使用就必须先定义函数指针!For example, void fun(); /*声明一个函数原型*/ void (*fun)(); /*声明一个函数指针*/ 获取一个函数指针大小的方法: unsigned psize = sizeof(void(*)()); 为函数指针声明类型定义: typedef void (*pfun)(); 三、回调函数的作用,应在什么情况下使用? void (*p) (); //p是指向某函数的指针 有了指针变量便可以赋值,值的内容是署名匹配的函数名和返回类型。 For example void func() { /* do something */ } p = func; p的赋值可以不同,但一定要是函数的地址,并且署名和返回类型相同。传递回调函数的地址给调用者。 现在可以将p传递给另一个函数(调用者)- caller(),它将调用p指向的函数,而此函数名是未知的: void caller(void(*ptr)())

{ ptr(); /* 调用ptr指向的函数 */ } void func(); int main() { p = func; caller(p); /* 传递函数地址到调用者 */ }

回调函数和消息响应的区别

回调函数、消息和事件例程 调用(calling)机制从汇编时代起已经大量使用:准备一段现成的代码,调用者可以随时跳转至此段代码的起始地址,执行完后再返回跳转时的后续地址。CPU为此准备了现成的调用指令,调用时可以压栈保护现场,调用结束后从堆栈中弹出现场地址,以便自动返回。借堆栈保护现场真是一项绝妙的发明,它使调用者和被调者可以互不相识,于是才有了后来的函数和构件,使吾辈编程者如此轻松愉快。若评选对人类影响最大之发明,在火与车轮之后,笔者当推压栈调用。 话虽这样说,此调用机制并非完美。回调函数就是一例。函数之类本是为调用者准备的美餐,其烹制者应对食客了如指掌,但实情并非如此。例如,写一个快速排序函数供他人调用,其中必包含比较大小。麻烦来了:此时并不知要比较的是何类数据--整数、浮点数、字符串?于是只好为每类数据制作一个不同的排序函数。更通行的办法是在函数参数中列一个回调函数地址,并通知调用者:君需自己准备一个比较函数,其中包含两个指针类参数,函数要比较此二指针所指数据之大小,并由函数返回值说明比较结

果。排序函数借此调用者提供的函数来比较大小,借指针传递参数,可以全然不管所比较的数据类型。被调用者回头调用调用者的函数(够咬嘴的),故称其为回调(callback)。 回调函数使程序结构乱了许多。Windows API 函数集中有不少回调函数,尽管有详尽说明,仍使初学者一头雾水。恐怕这也是无奈之举。无论何种事物,能以树形结构单向描述毕竟让人舒服些。如果某家族中孙辈又是某祖辈的祖辈,恐怕无人能理清其中的头绪。但数据处理之复杂往往需要构成网状结构,非简单的客户/服务器关系能穷尽。 Windows 系统还包含着另一种更为广泛的回调机制,即消息机制。消息本是Windows 的基本控制手段,乍看与函数调用无关,其实是一种变相的函数调用。发送消息的目的是通知收方运行一段预先准备好的代码,相当于调用一个函数。消息所附带的WParam 和LParam 相当于函数的参数,只不过比普通参数更通用一些。应用程序可以主动发送消息,更多情况下是坐等Windows 发送消息。一旦消息进入所属消息队列,便检感兴趣的那些,跳转去执行相应的消息处理代码。操作系统本是为应用程序服务,由应用程序来调用。而应用程序一旦启动,

在vb中调用dll的方法

1 制作好DLL之后,就可以用VB调用它,实现VB调用C程序。VB程序要使用DLL中的函数,首先必须要有特殊的声明,用Declare声明语句在窗体级或模块级或全局模块的代码声明段进行声明,将动态链接库中的函数声明到VB中,供VB程序调用。 语句格式为:Declare Sub 过程名Lib [ Alias " 别名]([ByVal 参数AS类型]),或为Declare Function函数名Lib [Alias " 别名]([ByVal 参数AS类型])AS类型在声明中首先用Declare 关键字表示声明DLL中的函数。在C语言中有的函数类型为VOID,它表示不具有返回值,则必须用关键字Sub将其声明成过程。有的函数具有返回值,则必须用关键字Function将其声明成函数,并且在声明语句的最后要用AS关键字指明函数返回值的类型。 例如上面的ADD.DLL在VB中就可以声明为: Decl are Function ADD Lib “c:\ADD.dll” (ByVal X AS Integer, ByVal Y AS Integer ,ByVal filein asstring)AS Integer 通过此声明语句将函数ADD声明到VB中,便可直接调用。 2、dll文件中的函数好像是C语言写的, // 函数名:int __stdcall GetMacNo(int *MacNo) // 功能:获取卡机的卡机号(单机时) // 参数: MacNo[0]-被读出的卡机号 // 返回值:0-成功, // 2-PC接收超时, // 3-应答错误 dll的文件名是COMM232.dll 函数的形参int *MacNo是指针吗? 在VB中应该怎么声明和调用该函数? VB里也可以定义指针吗? 问题补充:vb调用dll文件中的函数我是会的,但这儿的形参有一个星号才不知是怎么一回事, 我是这样声明的对吗? Public Declare Function GetMacNo Lib "COMM232.dll" (ByVal MacNo As Integer) As Integer 又应该怎么调用呢?要先定义一个指针的变量再传给*MacNo还是要怎么做? 都说了MacNo是被读出的卡机号,那么就是传址的了。 dim l as integer dim m as integer l=GetMacNo(m) if l=0 then label1.caption="卡机号: " & m elseif l=2 then msgbox "PC接收超时" elseif l=3 then msgbox "应答错误" end if

钩子函数和回调函数

钩子函数和回调函数 对应关系:Specifies the type of hook procedure to be installed. This parameter can be one of the following values. Value Description WH_CALLWNDPROC Installs a hook procedure that monitors messages before the system sends them to the destination window procedure. For more information, see the CallWndProc hook procedure. WH_CALLWNDPROCRET Installs a hook procedure that monitors messages after they have been processed by the destination window procedure. For more information, see the CallWndRetProc hook procedure. WH_CBT Installs a hook procedure that receives notifications useful to a computer-based training (CBT) application. For more information, see the CBTProc hook procedure. WH_DEBUG Installs a hook procedure useful for debugging other hook procedures. For more information, see the DebugProc hook procedure.

关于DLL动态库调用

关于DLL动态库调用小结 引言 比较大的应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作。可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用。在构造软件系统时,如果将所有模块的源代码都静态编译到整个应用程序EXE 文件中,会产生一些问题:一个缺点是增加了应用程序的大小,它会占用更多的磁盘空间,程序运行时也会消耗较大的内存空间,造成系统资源的浪费;另一个缺点是,在编写大的EXE程序时,在每次修改重建时都必须调整编译所有源代码,增加了编译过程的复杂性,也不利于阶段性的单元测试。 Windows系统平台上提供了一种完全不同的较有效的编程和运行环境,你可以将独立的程序模块创建为较小的DLL(Dynamic Linkable Library)文件,并可对它们单独编译和测试。在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。Windows自己就将一些主要的系统功能以DLL 模块的形式实现。 一般来说,DLL是一种磁盘文件,以.dll、.DRV、.FON、.SYS和许多以.EXE为扩展名的系统文件都可以是DLL。它由全局数据、服务函数和资源组成,在运行时被系统加载到进程的虚拟空间中,成为调用进程的一部分。如果与其它DLL之间没有冲突,该文件通常映射到进程虚拟空间的同一地址上。DLL模块中包含各种导出函数,用于向外界提供服务。DLL可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个DLL在内存中只有一个实例;DLL实现了代码封装性;DLL的编制与具体的编程语言及编译器无关。 在Win32环境中,每个进程都复制了自己的读/写全局变量。如果想要与其它进程共享内存,必须使用内存映射文件或者声明一个共享数据段。DLL模块需要的堆栈内存都是从运行进程的堆栈中分配出来的。Windows在加载DLL模块时将进程函数调用与DLL文件的导出函数相匹配。Windows操作系统对DLL的操作仅仅是把DLL映射到需要它的进程的虚拟地址空间里去。DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有. 调用方式

相关文档
最新文档