歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C++回調函數(callback)的使用

什麼是回調函數(callback)

    模塊A有一個函數foo,它向模塊B傳遞foo的地址,然後在B裡面發生某種事件(event)時,通過從A裡面傳遞過來的foo的地址調用foo,通知A發生了什麼事情,讓A作出相應反應。 那麼我們就把foo稱為回調函數。
   
例子:
      回調函數是一個很有用,也很重要的概念。當發生某種事件時,系統或其他函數將會自動調用你定義的一段函數。回調函數在windows編程使用的場合很多, 比如Hook回調函數:MouseProc,GetMsgProc以及EnumWindows,DrawState的回調函數等等,還有很多系統級的回調 過程。本文不准備介紹這些函數和過程,而是談談實現自己的回調函數的一些經驗。
      之所以產生使用回調函數這個想法,是因為現在使用VC和Delphi混合編程,用VC寫的一個DLL程序進行一些時間比較長的異步工作,工作完成之後,需 要通知使用DLL的應用程序:某些事件已經完成,請處理事件的後續部分。開始想過使用同步對象,文件影射,消息等實現DLL函數到應用程序的通知,後來突 然想到可不可以在應用程序端先寫一個函數,等需要處理後續事宜的時候,在DLL裡直接調用這個函數即可。  

       於是就動手,寫了個回調函數的原形。在VC和 Delphi裡都進行了測試

一:聲明回調函數類型。
        vc版
               typedef int (WINAPI *PFCALLBACK)(int Param1,int Param2) ;
        Delph版
               PFCALLBACK = function(Param1:integer;Param2:integer):integer;stdcall;
        實際上是聲明了一個返回值為int,傳入參數為兩個int的指向函數的指針。
        由於C++和PASCAL編譯器對參數入棧和函數返回的處理有可能不一致,把函數類型用WINAPI(WINAPI宏展開就是__stdcall)或stdcall統一修飾。
二:聲明回調函數原形
        聲明函數原形
       vc版
                int WINAPI CBFunc(int Param1,int Param2);
        Delphi版
           function CBFunc(Param1,Param2:integer):integer;stdcall;             

       以上函數為全局函數,如果要使用一個類裡的函數作為回調函數原形,把該類函數聲明為靜態函數即可。

三: 回調函數調用調用者
          調用回調函數的函數我把它放到了DLL裡,這是一個很簡單的VC生成的WIN32 DLL.並使用DEF文件輸出其函數名 TestCallBack。實現如下:
               PFCALLBACK   gCallBack=0;
             void WINAPI TestCallBack(PFCALLBACK Func)
            {
                   if(Func==NULL)return;
                   gCallBack=Func;
                   DWORD ThreadID=0;
                   HANDLE hThread = CreateThread(   NULL,   NULL,   Thread1,    LPVOID(0),           &ThreadID );
                    return;
              }
       此函數的工作把傳入的 PFCALLBACK Func參數保存起來等待使用,並且啟動一個線程。聲明了一個函數指針PFCALLBACK gCallBack保存傳入的函數地址。
四: 回調函數如何被使用:
           TestCallBack函數被調用後,啟動了一個線程,作為演示,線程人為的進行了延時處理,並且把線程運行的過程打印在屏幕上.
本段線程的代碼也在DLL工程裡實現
       ULONG   WINAPI Thread1(LPVOID Param)
      {
              TCHAR Buffer[256];
              HDC hDC = GetDC(HWND_DESKTOP);
              int Step=1;
              MSG Msg;

   DWORD StartTick;
         //一個延時循環
              for(;Step<200;Step++)
              {
                         StartTick = GetTickCount();
                   /*這一段為線程交出部分運行時間以讓系統處理其他事務*/
                        for(;GetTickCount()-StartTick<10;)
                          {
                                  if(PeekMessage(&Msg,NULL,0,0,PM_NOREMOVE) )
                                  {
                                    TranslateMessage(&Msg);
                                    DispatchMessage(&Msg);
                                    }
                            }  

                       /*把運行情況打印到桌面,這是vcbear調試程序時最喜歡干的事情*/
            sprintf(Buffer,"Running %04d",Step);
                          if(hDC!=NULL)
                                   TextOut(hDC,30,50,Buffer,strlen(Buffer));
                    }
                 /*延時一段時間後調用回調函數*/  
                 (*gCallback)(Step,1);
                  /*結束*/
                    ::ReleaseDC (HWND_DESKTOP,hDC);
                   return 0;
       }

Copyright © Linux教程網 All Rights Reserved