Lv.的博客

MFC的回调函数

 

MFC中应该有两类回调函数:一类是源自C的传统回调函数,此类回调函数若非定义为全局函数,而定义在类中的话,要添加static约束,常见的有EnumXXX();一类是消息响应函数,通过成员函数指针实现回调。

 

设想一种情况,基类A触发某事件E后,回调某定义好的函数F进行事件处理(MFC中表现为消息响应函数)。继承于类A的子类B和C,可能对于E有不同的处理方式,于是需要对基类A的函数F进行改写。自然而然的,我们想到将F定义为以virtual修饰的虚函数。

 

——————————————————————————————————————————————————————

回调函数的简单定义就是你定义的由Windows来调用。以下两个函数摘自《Programming Windows with MFC》,这里暂且不管函数的具体作用,在FillListBox中有一个API函数,它调用的回调函数是EnumFontFamProc,回调函数的声明形式一般都是相对固定的,具体可以参考MSDN。

 

[cpp] view plain copy
 
 print?
  1. static int CALLBACK EnumFontFamProc (ENUMLOGFONT* lpelf,NEWTEXTMETRIC* lpntm, int nFontType, LPARAM lParam);  
  2.   
  3. void CMainWindow::FillListBox ()  
  4.   
  5. {  
  6.     m_wndListBox.ResetContent ();  
  7.   
  8.     CClientDC dc (this);  
  9.   
  10.     ::EnumFontFamilies ((HDC) dc, NULL, (FONTENUMPROC) EnumFontFamProc,(LPARAM) this);  
  11.   
  12. }  
  13.   
  14. int CALLBACK CMainWindow::EnumFontFamProc (ENUMLOGFONT* lpelf,NEWTEXTMETRIC* lpntm, int nFontType, LPARAM lParam)  
  15. {  
  16.     CMainWindow* pWnd = (CMainWindow*) lParam;  
  17.   
  18.     if ((pWnd->m_wndCheckBox.GetCheck () == BST_UNCHECKED) || (nFontType & TRUETYPE_FONTTYPE))  
  19.   
  20.         pWnd->m_wndListBox.AddString (lpelf->elfLogFont.lfFaceName);  
  21.   
  22.     return 1;  
  23.   
  24. }  

 

请注意这里的函数EnumFontFamilies中的最后一个参数传递的是this即该CMainWindow对象的指针,为什么要这样呢,可以看到EnumFontFamProc的声明是static,在C++中static函数是不能调用非static成员的,所以这里传递一个this就不是很奇怪了。但是为什么要将该函数声明为static呢,这就要归咎于C++的特殊性了,众所周知C++编译器在编译的时候都会在对象中添加一个this指针,在成员函数调用中又会附加一个参数保存this指针,但是Windows的回调函数有严格的定义就是必须按照参数列表传递的参数,加了this指针后参数列表就会与Windows期望的参数列表不一致了,因此这里将其声明为static(static成员函数不会传递this指针,这点说起来总是知道,但是真正用时总是忘了,唉)。

       另外在Windows中使用callback函数很常见,恰好许多支持回调函数的API函数都像这里的EnumFontFamilies一样支持自定义的LPARAM参数,刚好可以传递this,如果使用的API函数不支持这样的自定义的LPARAM参数,就需要其他的方法了,一种比较简单的方法是将this复制为global变量使得回调函数可以使用。

 
 
posted @ 2017-03-02 14:44  Avatarx  阅读(1694)  评论(0编辑  收藏  举报