回调函数是怎么实现的为什么系统就会去调用回调函数

回调函数是怎么实现的为什么系统就会去调用回调函数,第1张

回调函数是应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理异步事件。应用程序把回调函数的地址指针告诉DLL,而DLL在适当的时候会调用该函数。回调函数必须遵守事先规定好的参数格式和传递方式,否则DLL一调用它就会引起程序或系统的崩溃。通常情况下,回调函数采用标准WindowsAPI的调用方式,即__stdcall,当然,DLL编制者可以自已定义调用方式,但客户程序也必须遵守相同的规定。在__stdcall方式下,函数的参数按从右到左的顺序压入堆栈,除了明确指明是指针或引用外,参数都按值传递,函数返回之前自己负责把参数从堆栈中d出。程序在调用一个函数(function)时(通常指api)相当于程序(program)呼叫(Call)了一个函数(function)关系表示如下: call(调用) program --------------------→ dll 程序在调用一个函数时,将自己的函数的地址作为参数传递给程序调用的函数时(那么这个自己的函数称回调函数)需要回调函数的 DLL 函数往往是一些必须重复执行某些 *** 作的函数关系表示如下: call(调用) program --------------------→ dll ↑ ¦ ¦_______________________________¦ callback(回调)当你调用的函数在传递返回值给回调函数时,你就可以利用回调函数来处理或完成一定的 *** 作。至于如何定义自己的回调函数,跟具体使用的API函数有关,很多不同类别的回调函数有各种各样的参数,有关这些参数的描述一般在帮助中有说明回调函数的参数和返回值等其实简单说回调函数就是你所写的函数满足一定条件后,被DLL调用! Windows 系统还包含着另一种更为广泛的回调机制,即消息机制。消息本是 Windows 的基本控制手段,是一种变相的函数调用。发送消息的目的是通知收方运行一段预先准备好的代码,相当于调用一个函数。消息所附带的 WParam 和 LParam 相当于函数的参数,应用程序可以主动发送消息,更多情况下是坐等 Windows 发送消息。一旦消息进入所属消息队列,便检感兴趣的那些,跳转去执行相应的消息处理代码。 *** 作系统本是为应用程序服务,由应用程序来调用。而应用程序一旦启动,却要反过来等待 *** 作系统的调用。这分明也是一种回调,或者说是一种广义回调。其实,应用程序之间也可以形成这种回调。假如进程 B 收到进程 A 发来的消息,启动了一段代码,其中又向进程 A 发送消息,这就形成了回调。这种回调比较隐蔽,弄不好会搞成递归调用,若缺少终止条件,将会循环不已,直至把程序搞垮。利用消息也可以构成狭义回调。把回调函数地址换成窗口 handle。如此,当需要比较数据大小时,不是去调用回调函数,而是借 API 函数 SendMessage 向指定窗口发送消息。收到消息方负责比较数据大小,把比较结果通过消息本身的返回值传给消息发送方。所实现的功能与回调函数并无不同。当然,此例中改为消息纯属画蛇添脚,反倒把程序搞得很慢。但其他情况下并非总是如此,特别是需要异步调用时,发送消息是一种不错的选择。假如回调函数中包含文件处理之类的低速处理,调用方等不得,需要把同步调用改为异步调用,去启动一个单独的线程,然后马上执行后续代码,其余的事让线程慢慢去做。一个替代办法是借 API 函数 PostMessage 发送一个异步消息,然后立即执行后续代码。这要比自己搞个线程省事许多,而且更安全。 只要与编程有关,无论何事都离不开 object。但 object 并未消除回调,反而把它发扬光大,弄得到处都是,只不过大都以事件(event)的身份出现,镶嵌在某个结构之中,显得更正统,更容易被人接受。应用程序要使用某个构件,总要先弄清构件的属性、方法和事件,然后给构件属性赋值,在适当的时候调用适当的构件方法,还要给事件编写处理例程,以备构件代码来调用。何谓事件它不过是一个指向事件例程的地址,与回调函数地址没什么区别。不过,此种回调方式比传统回调函数要高明许多。首先,它把让人不太舒服的回调函数变成一种自然而然的处理例程,使编程者顿觉气顺。再者,地址是一个危险的东西,用好了可使程序加速,用不好处处是陷阱,程序随时都会崩溃。现代编程方式总是想法把地址隐藏起来(隐藏比较彻底的如 VB 和 Java),其代价是降低了程序效率。事件例程()使编程者无需直接 *** 作地址,但并不会使程序减速。 回调用于层间协作,上层将本层函数安装在下层,这个函数就是回调,而下层在一定条件下触发回调,例如作为一个驱动,是一个底层,他在收到一个数据时,除了完成本层的处理工作外,还将进行回调,将这个数据交给上层应用层来做进一步处理,这在分层的数据通信中很普遍。其实回调和API非常接近,他们的共性都是跨层调用的函数。但区别是API是低层提供给高层的调用,一般这个函数对高层都是已知的;而回调正好相反,他是高层提供给底层的调用,对于低层他是未知的,必须由高层进行安装,这个安装函数其实就是一个低层提供的API,安装后低层不知道这个回调的名字,但它通过一个函数指针来保存这个回调,在需要调用时,只需引用这个函数指针和相关的参数指针。 其实:回调就是该函数写在高层,低层通过一个函数指针保存这个函数,在某个事件的触发下,低层通过该函数指针调用高层那个函数。 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础。 对于不同类型的语言(如结构化语言和对象语言)、平台(Win32、JDK)或构架(CORBA、DCOM、WebService),客户和服务的交互除了同步方式以外,都需要具备一定的异步通知机制,让服务方(或接口提供方)在某些情况下能够主动通知客户,而回调是实现异步的一个最简捷的途径。 对于一般的结构化语言,可以通过回调函数来实现回调。回调函数也是一个函数或过程,不过它是一个由调用方自己实现,供被调用方使用的特殊函数。在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类成为回调类,回调类的对象成为回调对象。对于象C++或Object Pascal这些兼容了过程特性的对象语言,不仅提供了回调对象、回调方法等特性,也能兼容过程语言的回调函数机制。 Windows平台的消息机制也可以看作是回调的一种应用,我们通过系统提供的接口注册消息处理函数(即回调函数),从而实现接收、处理消息的目的。由于Windows平台的API是用C语言来构建的,我们可以认为它也是回调函数的一个特例。 对于分布式组件代理体系CORBA,异步处理有多种方式,如回调、事件服务、通知服务等。事件服务和通知服务是CORBA用来处理异步消息的标准服务,他们主要负责消息的处理、派发、维护等工作。对一些简单的异步处理过程,我们可以通过回调机制来实现。

大致思路就是只要不把他们放在一个主程序内就OK了,放在同一个文件或者不同f文件都是一样的。对于第二个问题,回答也是可以的

比如说这样的程序调用:

PROGRAM

MAIN

CALL

SUB1

END

SUBROUTINE

S

CALL

SUB2

END

SUBROUTINE

SUB2()

CALL

SUB3

END

SUBROUTINE

SUB3()

END

这几个子程序和主程序PROGRAM

MAIN可以放在同一个f文件里面编译,也可以分别放置不同f文件,编译时效果一样。

问题描述 该函数在win平台上面调用不是很成功 GUI会可以调出来 但可能和屏蔽调其中的一些用到CUI的功能 而调用CUI如ma exe是很不成功 出现一个黑屏 没用内容 或者根本不有结果 其程序如下 class RunThread{ Process t public void run(){ try{ t = java lang Runtime getRuntime() exec( c:\\ma exe ); }catch(java io IOException e ) { System out println(e); }}}//class RunExeNative{ public static void main(String args[]){  RunThread RT = new RunThread(); RT run(); }}下面是JNI + C 的本地化的实现方法 写一个 CallExeNative h步骤如下 step one :/ CallExeNative java /编写CallExeNative java文件import java lang ;class CallExeNative{  public native static void CEN();  static { System loadLibrary( CallExeNative ); }}在命令行里用:javac CallExeNative javajavah CallExeNative然后你就多了一个 CallExeNative h它的文件如下 / DO NOT EDIT THIS FILE it is machine generated /#include <jni h>/ Header for class CallExeNative /#ifndef _Included_CallExeNative#define _Included_CallExeNative#ifdef __cplusplusextern C {#endif/ Class: CallExeNative Method:CEN Signature: ()V /JNIEXPORT void JNICALL Java_CallExeNative_CEN (JNIEnv jclass);#ifdef __cplusplus}#endif#endif这个文件不用改 下面要写一个CallExeNative c文件 该函数的功能是将你的CUI文件调出来文件如下 #include C:\CallExeNative h /在你的机器上调试时可能要修改该文件路径/#include <stdio h>#include <process h>#include <conio h>JNIEXPORT void JNICALL Java_CallExeNative_CEN(JNIEnv env jclass cl){char prog[ ];printf( Hello CallExeNative!\n );  printf( Enter name of program to exec: );  gets( prog );  _execl( prog prog _execl o NULL );}现在visual c++ 的cl 功能在命令行下c:\>cl /LD CallExeNative c之后你 会发现生成了一个CallExeNative dll文件 现在写RunExeNative java文件 /includeCallExeNative hCallExeNative dll/import java lang ;/load a native method : to call a native file/class CallExeNative{  public native static void CEN();  static { System loadLibrary( CallExeNative ); }}//class RunExeNative{ public static void main(String args[]){ CallExeNative CEN = new CallExeNative(); CEN CEN(); }}同样用javac RunExeNative javajava RunExeNative之后你就会发现提示你输入CUI文件的路径 你输入路径即可!说明 要注意的是CallExeNative h和CallExeNative dll应该都在同一个文件夹(我的是在c:\jdk _ \bin\) 不足之处 破坏了java的移植性!而且你想想看 同样的功能在VB下用Shell(filepath windowstyle)很容易就搞定 你还会用java吗?我写这篇文章的目的是希望大家找到一种更好的方法来实现这个功能 lishixinzhi/Article/program/Java/hx/201311/25805

1使用记事本(或其他文本编辑器)创建一个protocalreg文件(reg后缀的执行文件),并写入以下内容

Windows Registry Editor Version500[HKEY_CLASSES_ROOT\myWebshell]

@="URL:myWebshell Protocol Handler""URL Protocol"=""[HKEY_CLASSES_ROOT\myWebshell\DefaultIcon]

@="D:\\Program Files (x86)\\Tencent\\TIM\\Bin\\QQScLauncherexe"[HKEY_CLASSES_ROOT\myWebshell\shell]

[HKEY_CLASSES_ROOT\myWebshell\shell\open]

[HKEY_CLASSES_ROOT\myWebshell\shell\open\command]

@="\"D:\\Program Files (x86)\\Tencent\\TIM\\Bin\\QQScLauncherexe\" \"%1\""

2 修改参数

使用记事本打开文件后,按照下图说明修改相关参数

21修改连接名称

修改红框内名称自定义即可,全部使用英文字符(该名称即为调用时的href),共六处

22修改可执行文件路径

修改红框内可执行文件路径,共两处,需注意: 文件路径中使用//分割

3 执行protocalreg文件

4 创建调用连接

连接地址为 步骤1中所命名的链接名称,后面加://hello,(hello为传递参数,可任意添加)

5查看效果

以上就是关于回调函数是怎么实现的为什么系统就会去调用回调函数全部的内容,包括:回调函数是怎么实现的为什么系统就会去调用回调函数、fortran主程序调用一个子程序,子程序又调用另一个子程序,如何编译。、在 java 里面调用 CUI 程序的方法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/10115549.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-05
下一篇2023-05-05

发表评论

登录后才能评论

评论列表(0条)

    保存