轉自:http://blog.csdn.net/sizheng0320/article/details/1615777
ms-help://MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconusingcallbackfunctions.htm
回調函數是托管應用程序中可幫助非托管 DLL 函數完成任務的代碼。對回調函數的調用將從托管應用程序中,通過一個 DLL 函數,間接地傳遞給托管實現。在用平台調用調用的多種 DLL 函數中,有些函數要求正確地運行托管代碼中的回調函數。本主題將介紹托管函數的元素,並說明如何實現回調函數和從托管代碼中調用回調函數。
回調函數基礎
要從托管代碼中調用大多數 DLL 函數,可創建該函數的托管定義,然后調用該函數。此過程比較直接。
要使用需要回調函數的 DLL 函數,則會有一些附加的步驟。首先,必須在文檔中查閱該函數,確定該函數是否需要回調。接着,必須在托管應用程序中創建回調函數。最后,調用該 DLL 函數,並將指向回調函數的指針當作參數進行傳遞。下圖總結了這些步驟。
回調函數和實現
回調函數非常適合在重復執行任務的情況下使用。另一個常見用途是與枚舉函數(如 Win32 API 中的EnumFontFamilies、EnumPrinters 和 EnumWindows)一起使用。如下一節中的示例所示,EnumWindows 函數將枚舉計算機上的所有現有窗口,並調用回調函數來對每個窗口執行一項任務。
實現回調函數
以下過程將說明托管應用程序如何使用平台調用來輸出本地計算機上每個窗口的句柄值。尤其是,示例將使用EnumWindows 函數來逐步瀏覽窗口列表,並使用一個托管回調函數(名為 CallBack)來輸出窗口句柄的值。
實現回調函數
- 開始實現之前,先查看 EnumWindows 函數的簽名。EnumWindows 具有以下簽名:
BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
表示此函數需要回調的線索之一是存在 lpEnumFunc 參數。如果參數采用指向回調函數的指針,其名稱中通常會有 lp(長指針)前綴與 Func 后綴的組合。有關 Win32 函數的文檔,請參見 Microsoft Platform SDK。
- 創建托管回調函數。該示例聲明一個名為
CallBack
的委托類型,此委托類型采用兩個參數:hwnd 和lparam。第一個參數是窗口的句柄;第二個參數由應用程序定義。在此版本中,這兩個參數都必須是整數。回調函數通常會返回非零值來表示成功,返回零來表示失敗。本示例將返回值顯式設置為 true,以繼續進行枚舉。
- 創建一個委托,並將其作為參數傳遞給 EnumWindows 函數。平台調用會自動將委托轉換為常見的回調格式。
- 確保在回調函數完成其工作之前,垃圾回收器不會回收委托。如果委托作為參數進行傳遞,或者所包含的委托作為結構中的字段進行傳遞,則該委托在調用期間不會被回收。因此,正如下面的枚舉示例所示,回調函數會在調用返回前完成其工作,而無需托管調用方執行額外的操作。
然而,如果可以在調用返回后調用回調函數,則托管調用方必須采取相應的措施來確保委托在回調函數完成其工作之前不會被回收。有關防止垃圾回收的詳細信息,請參見用平台調用進行 Interop 封送處理。
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace MyDelegate
{
#region 委托實現回調函數
public delegate bool CallBack( int hwnd, int lParam);
public class EnumReportApp
{
[DllImport( " user32 " )]
// user32.dll中的Win32函數原型為:
// BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
// 表示此函數需要回調的線索之一是存在 lpEnumFunc 參數。如果參數采用指向回調函數的指針,其名稱中通常會有 lp(長指針)前綴與 Func 后綴的組合。
// 這里在導入user32.dll后,引入該函數,但是已經將其第一個參數傳入了這里定義的委托函數CallBack
public static extern int EnumWindows(CallBack x, int y);
public static bool Report( int hwnd, int lParam)
{
Console.Write( " Window handle is " );
Console.WriteLine(hwnd);
return true ;
}
public static void Main()
{
// 實例化一個委托,其實現為上面定義的Report,即調用myCallBack時就是調用了Report
CallBack myCallBack = new CallBack(EnumReportApp.Report);
// 從這個.NET程序中調用外面user32.dll中的Win32的函數,但是該函數“向回調用(回調)”剛剛定義的.NET程序中的函數myCallBack
EnumWindows(myCallBack, 0 );
Console.ReadLine();
}
}
#endregion
}