⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 什么是回调函数(callback)_诸神的黄昏.htm

📁 最全的介绍C语言结构体的使用方法和使用技巧!
💻 HTM
📖 第 1 页 / 共 3 页
字号:
      /演示回调函数被调用</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
      end;</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用静态连接的方法连接DLL里的出口函数 
      TestCallBack,在工程里添加 Button( 
对于Delphi的工程,还需要在Form1上放一个Edit控件,默认名为Edit1)。</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 响应ButtonClick事件调用 
      TestCallBack</P>
      <P></P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
      TestCallBack(CBFunc) //函数的参数CBFunc为回调函数的地址</P>
      <P></P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
      函数调用创建线程后立刻返回,应用程序可以同时干别的事情去了。现在可以看到屏幕上不停的显示字符串,表示dll里创建的线程运行正常。一会之后,线程延时部分结束结束,vc的应用程序弹出MessageBox,表示回调函数被调用并显示根据Param1,Param2运算的结果,Delphi的程序edit控件里的文本则被改写成Param1,Param2 
      的运算结果。</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
      可见使用回调函数的编程模式,可以根据不同的需求传递不同的回调函数地址,或者定义各种回调函数的原形(同时也需要改变使用回调函数的参数和返回值约定),实现多种回调事件处理,可以使程序的控制灵活多变,也是一种高效率的,清晰的程序模块之间的耦合方式。在一些异步或复杂的程序系统里尤其有用 
      -- 
      你可以在一个模块(如DLL)里专心实现模块核心的业务流程和技术功能,外围的扩展的功能只给出一个回调函数的接口,通过调用其他模块传递过来的回调函数地址的方式,将后续处理无缝地交给另一个模块,随它按自定义的方式处理。</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
      本文的例子使用了在DLL里的多线程延时后调用回调函数的方式,只是为了突出一下回调函数的效果,其实只要是在本进程之内,都可以随你高兴可以把函数地址传递来传递去,当成回调函数使用。</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
      这样的编程模式原理非常简单单一:就是把函数也看成一个指针一个地址来调用,没有什么别的复杂的东西,仅仅是编程里的一个小技巧。至于回调函数模式究竟能为你带来多少好处,就看你是否使用,如何使用这种编程模式了。</P>
      <P><FONT color=#ff0000 size=6>另外的解释:<STRONG><FONT color=#3366cc 
      size=2>cdxiaogan</FONT></STRONG></FONT></P>
      <P>msdn上这么说的:<BR>有关函数指针的知识<BR>使用例子可以很好地说明函数指针的用法。首先,看一看 Win32 API 中的 
      EnumWindows 函数:</P>
      <P>Declare Function EnumWindows lib "user32" _<BR>(ByVal lpEnumFunc as 
      Long, _<BR>ByVal lParam as Long ) As Long</P>
      <P>EnumWindows 是一个枚举函数,它能够列出系统中每一个打开的窗口的句柄。EnumWindows 
      的工作方式是重复地调用传递给它的第一个参数(lpEnumFunc,函数指针)。每当 EnumWindows 调用函数,EnumWindows 
      都传递一个打开窗口的句柄。</P>
      <P>在代码中调用 EnumWindows 
      时,可以将一个自定义函数作为第一个参数传递给它,用来处理一系列的值。例如,可以编写一个函数将所有的值添加到一个列表框中,将 hWnd 
      值转换为窗口的名字,以及其它任何操作!</P>
      <P>为了表明传递的参数是一个自定义函数,在函数名称的前面要加上 AddressOf 关键字。第二个参数可以是合适的任何值。例如,如果要把 
      MyProc 作为函数参数,可以按下面的方式调用 EnumWindows:</P>
      <P>x = EnumWindows(AddressOf MyProc, 5)</P>
      <P>在调用过程时指定的自定义函数被称为回调函数。回调函数(通常简称为“回调”)能够对过程提供的数据执行指定的操作。</P>
      <P>回调函数的参数集必须具有规定的形式,这是由使用回调函数的 API 决定的。关于需要什么参数,如何调用它们,请参阅 API 
      文档。<BR><FONT color=#3366cc>回复人:<STRONG>zcchm</STRONG></FONT></P>
      <P>我谈一下自己对回调函数的一点理解, 不对的地方请指教.</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 我刚开始接触回调时, 也是一团雾水.很多人解释这个问题时, 总是拿API来举例子, 
      本来菜鸟最惧怕的就是API, ^_^. 回调跟API没有必然联系.</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 
      其实回调就是一种利用函数指针进行函数调用的过程.<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
      为什么要用回调呢?比如我要写一个子模块给你用, 来接收远程socket发来的命令.当我接收到命令后, 需要调用你的主模块的函数, 
      来进行相应的处理.但是我不知道你要用哪个函数来处理这个命令,&nbsp;&nbsp; 我也不知道你的主模块是什么.cpp或者.h, 或者说, 
      我根本不用关心你在主模块里怎么处理它, 也不应该关心用什么函数处理它...... 怎么办? </P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 使用回调.</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 我在我的模块里先定义回调函数类型, 
      以及回调函数指针.<BR>&nbsp;&nbsp;&nbsp;&nbsp; typedef void (CALLBACK 
      *cbkSendCmdToMain) (AnsiString sCmd);<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
      cbkSendCmdToMain&nbsp;&nbsp;&nbsp;&nbsp; 
      SendCmdToMain;<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
      这样SendCmdToMain就是一个指向拥有一个AnsiString形参, 返回值为void的函数指针.</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 这样, 在我接收到命令时, 
      就可以调用这个函数啦.<BR>&nbsp;&nbsp;&nbsp;&nbsp; ...<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
      SendCmdToMain(sCommand);<BR>&nbsp;&nbsp;&nbsp;&nbsp; ...</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 但是这样还不够, 我得给一个接口函数(比如Init), 
      让你在主模块里调用Init来注册这个回调函数.</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 在你的主模块里, 可能这样</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; void CALLBACK YourSendCmdFun(AnsiString 
      sCmd);&nbsp;&nbsp; //声明<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
      ...<BR>&nbsp;&nbsp;&nbsp;&nbsp; void CALLBACK YourSendCmdFun(AnsiString 
      sCmd);&nbsp;&nbsp; //定义<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
      {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
      ShowMessage(sCmd);<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
      }<BR>&nbsp;&nbsp;&nbsp;&nbsp; ...</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 调用Init函数向我的模块注册回调.可能这样:</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; Init(YourSendCmdFun, ...);</P>
      <P>&nbsp;&nbsp;&nbsp;&nbsp; 这样, 预期目的就达到了.</P>
      <P><BR>&nbsp;&nbsp;&nbsp;&nbsp; 需要注意一点, 回调函数一般都要声明为全局的. 如果要在类里使用回调函数, 
      前面需要加上 static&nbsp;&nbsp; , 其实也相当于全局的.<BR></P>
      <P><FONT color=#ff0000 
size=6></FONT></P><BR></DIV></TD></TR></TBODY></TABLE><BR>
<DIV class=opt><A title=查看该分类中所有文章 
href="http://hi.baidu.com/dreadlord1984/blog/category/&sup3;&Igrave;&ETH;ò&Eacute;è&frac14;&AElig;&iexcl;í&iexcl;è&Ouml;&ordf;&micro;&Agrave;">类别:程序设计№¤知道</A> 
| <A title=将此文章添加到百度搜藏 
onclick="window.open('http://cang.baidu.com/do/add?it='+encodeURIComponent('什么是回调函数(callback)'+'_百度空间')+'&amp;iu='+encodeURIComponent(location.href)+'&amp;fr=sp#nw=1','_s','scrollbars=no,width=600,height=450,right=75,top=20,status=no,resizable=yes'); return false;" 
href="http://cang.baidu.com/do/add" target=_blank>添加到搜藏</A> | 浏览(<SPAN 
id=result></SPAN>) </DIV>
<DIV class=line></DIV>
<DIV id=in_reader>
<DIV class=tit>最近读者:</DIV>
<TABLE width="100%">
  <TBODY>
  <TR>
    <TD align=middle width="10%"><IMG height=55 
      src="什么是回调函数(callback)_诸神的黄昏.files/portraitn.jpg" width=55 
    border=0><BR>&nbsp;</TD>
    <TD align=left width="100%">
      <SCRIPT>document.write("<a href='http://passport.baidu.com/?login&tpl=sp&tpl_reg=sp&u="+myref+"' target='_self'>登录</a>后,您就出现在这里。");</SCRIPT>
    </TD>
    <TD width="100%"></TD></TR></TBODY></TABLE></DIV>
<DIV class=line></DIV>
<SCRIPT language=JavaScript>
allkey=allkey+"976f73c2d95db935e5dd3b1a_19f10ad3bbcb18013bf3cf57_";
</SCRIPT>

<DIV id=in_comment><A name=comment></A>
<DIV class=tit>网友评论:</DIV>
<SCRIPT>
function writecmt(type,id,cmtname,cmturl,cmttime){
	var html1="";
	if(type==1){
		if(cmturl==""){
			html1="<a name='"+id+"'>"+cmtname+"</a> - <span class='date'>"+cmttime+"</span> ";
		}else{
			html1="<a name='"+id+"' href='"+cmturl+"' target='_blank' title='"+cmturl+"'>"+cmtname+"</a> - <span class='date'>"+cmttime+"</span> ";
		}
	}else{
		if(cmtname=="匿名网友"){
			if(cmturl==""){
				html1="<a name='"+id+"'>"+cmtname+"</a> - <span class='date'>"+cmttime+"</span> ";
			}else{
				html1="<a name='"+id+"' href='"+cmturl+"' target='_blank' title='"+cmturl+"'>"+cmtname+"</a> - <span class='date'>"+cmttime+"</span>";
			}
		}else{
			if(cmturl==""){
				html1="<div class='f14' style='display:inline'>网友:<a name='"+id+"'>"+cmtname+"</a> - <span class=\"date\">"+cmttime+"</span></div>";
			}else{
				html1="<div class='f14' style='display:inline'>网友:<a name='"+id+"' href='"+cmturl+"' target='_blank' title='"+cmturl+"'>"+cmtname+"</a> - <span class=\"date\">"+cmttime+"</span></div>";
			}
		}
	}
	document.write(html1);
}

</SCRIPT>

<DIV id=page></DIV></DIV>
<DIV id=in_send>
<FORM id=popFormSubmit name=form1 onsubmit="return checkcmtform()" 
action=/dreadlord1984/commit method=post><INPUT type=hidden value=8 name=ct> 
<INPUT type=hidden value=1 name=cm> <INPUT type=hidden 
value=19f10ad3bbcb18013bf3cf57 name=spBlogID>
<SCRIPT language=JavaScript>
	document.write("<input type='hidden' name='spRefURL' value='"+window.location.href+"'>");
</SCRIPT>
 
<DIV class=tit>发表评论:</DIV>
<TABLE cellSpacing=5 cellPadding=0 width=620 border=0>
  <TBODY>
  <TR>
    <TD class=f14>姓 名:</TD>
    <TD><INPUT id=spBlogCmtor style="WIDTH: 220px" onfocus=hidErr(1); 
      tabIndex=1 maxLength=49 onchange="checkname('spBlogCmtor')" 
      name=spBlogCmtor>
      <SCRIPT>
document.write(" &nbsp;&nbsp; <a href='http://passport.baidu.com/?reg&tpl=sp&return_method=get&skip_ok=1&u=http://hi.baidu.com/sys/reg/' target='_blank'>注册</a>");
document.write(" | <a href='http://passport.baidu.com/?login&tpl=sp&tpl_reg=sp&u="+myref+"'>登录</a>");

</SCRIPT>
       
      <DIV id=nmerror style="DISPLAY: none">*姓名最长为50字节</DIV></TD></TR>
  <TR id=1_err style="DISPLAY: none">
    <TD>&nbsp;</TD>
    <TD>
      <DIV class=error id=1_err_con></DIV></TD></TR>
  <TR>
    <TD class=f14>网址或邮箱:</TD>
    <TD><INPUT id=spBlogCmtURL style="WIDTH: 360px" onfocus=hidErr(2); 
      tabIndex=2 maxLength=128 onchange="checkeandu('spBlogCmtURL')" 
      name=spBlogCmtURL> (选填)</TD>
    <SCRIPT>
G("spBlogCmtor").value="";
G("spBlogCmtURL").value="";
</SCRIPT>
  </TR>
  <TR id=2_err style="DISPLAY: none">
    <TD>&nbsp;</TD>
    <TD>
      <DIV class=error id=2_err_con></DIV></TD></TR>
  <TR>
    <TD class=f14 vAlign=top>内 容:</TD>
    <TD><TEXTAREA id=spBlogCmtText style="WIDTH: 520px; HEIGHT: 155px" onfocus=hidErr(3); tabIndex=3 name=spBlogCmtText></TEXTAREA>
      <SCRIPT>
G("spBlogCmtor").value=G("spBlogCmtor").defaultValue;
G("spBlogCmtText").value="";
</SCRIPT>
       </TD></TR>
  <TR id=3_err style="DISPLAY: none">
    <TD>&nbsp;</TD>
    <TD>
      <DIV class=error id=3_err_con></DIV></TD></TR>
  <TR id=vercode>
    <TD class=f14 vAlign=top>验证码:</TD>
    <TD vAlign=top><INPUT type=hidden 
      value=1B75981163D8F52CA0921AAB4BF57FC5BB118BCBA0FEBA8BE686B44712949A8C31B0E94A8D236716EEE205F55B33BED6EC03EFA42531BE3AE0EC48B384236852 
      name=spVcode> <INPUT id=spVerifyKey tabIndex=4 maxLength=4 size=6 
      name=spVerifyKey autocomplete="off">请输入下图中的四位验证码,字母不区分大小写。<BR>
      <SCRIPT language=JavaScript>

			var imgsrc="http://post.baidu.com/cgi-bin/genimg?1B75981163D8F52CA0921AAB4BF57FC5BB118BCBA0FEBA8BE686B44712949A8C31B0E94A8D236716EEE205F55B33BED6EC03EFA42531BE3AE0EC48B384236852";
			document.write("<img id='verifypic' src='"+imgsrc+"' width='120' height='40'>");

			function newverifypic(){
				document.getElementById("verifypic").src = imgsrc +"&t="+ Math.random();
			}
		</SCRIPT>
      <A title=看不清左边的字符 href="javascript:newverifypic();">看不清?</A> </TD></TR>
  <TR>
    <TD class=f14 vAlign=top>&nbsp;</TD>
    <TD class=f14 vAlign=top><INPUT id=btn_ok tabIndex=5 type=submit value=发表评论 name=btn_ok></TD></TR></TBODY></TABLE></FORM></DIV><BR></DIV>
<TABLE height=8 cellSpacing=0 cellPadding=0 width="100%" border=0>
  <TBODY>
  <TR>
    <TD class=modbl width=7>&nbsp;</TD>
    <TD class=modbc>&nbsp;</TD>
    <TD class=modbr width=7>&nbsp;</TD></TR></TBODY></TABLE></DIV></DIV></DIV></DIV>
<SCRIPT language=javascript>
<!--
var hstr="/dreadlord1984/brwstat?key1=1";
document.write("<script src='"+hstr+"&key2="+allkey+"'><\/script>");
//-->
</SCRIPT>
<BR>
<CENTER>
<DIV id=ft>&copy;2007 Baidu</DIV></CENTER>
<SCRIPT>
if(document.getElementById("m_blog"))
{
	var imgarray = document.getElementById("m_blog").getElementsByTagName('img');
	var imgw = document.getElementById("m_blog").offsetWidth;
	imgw =imgw-40;
	for(var i=0; i<imgarray.length; i++){
	if(imgarray[i].className=="blogimg" && imgarray[i].width>=imgw) imgarray[i].width=imgw;
	}
}
</SCRIPT>
</CENTER><IMG style="DISPLAY: none" src=""> </BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -