聲明:網絡上相似的中文博客大有存在,本人知識水平有限,業餘愛好,也是爲了備份收藏How to make a callback to C# from C/C++ code網絡
本着共享知識的初衷,翻譯一份給你們參考,爲了便於閱讀不至於拗口,沒有按照原文直譯,不到之處或者翻譯有誤,還望勿噴,敬請指評。函數
幾乎每一個人都知道怎樣調用一個非託管DLL中的函數,然而有時候咱們但願能從C/C++代碼中調用C#代碼。
想象一個場景,其中有一個名爲Engine.dll的本機C語言編寫DLL的C#應用程序。在DLL中有一個名爲「DoWork」
的函數入口點,我須要對它進行調用。在Engine.dll中調用"DoWork"就像在C#代碼中作如下聲明同樣簡單。spa
[DllImport("Engine.dll")] public static extern void DoWork();
這段代碼運行將很是良好,然而,讓我再假設一下DoWork是一個連續性運行的任務,爲了保證咱們的用戶端可被更新,
咱們但願顯示一個進度。想要實現這一點,咱們須要作出如下幾步:翻譯
1.在C#代碼中定義一個相似的非託管代碼委託code
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate void ProgressCallback(int value);
2.在C代碼中定義一個回調簽名orm
typedef void (__stdcall * ProgressCallback)(int);
3.在C代碼中更改DoWork的簽名以便接收ProgressCallback的地址blog
DLL void DoWork(ProgressCallback progressCallback)
注意:DLL宏的聲明是這樣的ip
#define DLL __declspec(dllexport)
4.在C#代碼中,咱們須要建立一個非託管委託類型的委託get
ProgressCallback callback = (value) => { Console.WriteLine("Progress = {0}", value); };
5.而後爲了調用DoWork,咱們須要這樣作編譯器
DoWork(callback);
這裏有一個簡單應用程序的示例源碼.這個代碼段包含其餘代碼套方案,其中有一個名爲ProcessFile函數的C代碼須要回調到C#,以便得到文件
路徑進行用於進一步處理 - 當前情形下將打印文件的內容到控制檯。
Engine.dll/Main.h
#include "Windows.h" #ifdef __cplusplus extern "C" { #endif #define DLL __declspec(dllexport) typedef void (__stdcall * ProgressCallback)(int); typedef char* (__stdcall * GetFilePathCallback)(char* filter); DLL void DoWork(ProgressCallback progressCallback); DLL void ProcessFile(GetFilePathCallback getPath); #ifdef __cplusplus } #endif
Engine.dll/Main.c
#include "Main.h" #include <stdio.h> DLL void DoWork(ProgressCallback progressCallback) { int counter = 0; for(; counter<=100; counter++) { // do the work... if (progressCallback) { // send progress update progressCallback(counter); } } } DLL void ProcessFile(GetFilePathCallback getPath) { if (getPath) { // get file path... char* path = getPath("Text Files|*.txt"); // open the file for reading FILE *file = fopen(path, "r"); // read buffer char line[1024]; // print file info to the screen printf("File path: %s\n", path ? path : "N/A"); printf("File content:\n"); while(fgets(line, 1024, file) != NULL) { printf("%s", line); } // close the file fclose(file); } }
TestApp.exe/Program.cs
using System; using System.Runtime.InteropServices; using System.Windows.Forms; class Program { [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate void ProgressCallback(int value); [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate string GetFilePathCallback(string filter); [DllImport("Engine.dll")] public static extern void DoWork([MarshalAs(UnmanagedType.FunctionPtr)] ProgressCallback callbackPointer); [DllImport("Engine.dll")] public static extern void ProcessFile([MarshalAs(UnmanagedType.FunctionPtr)] GetFilePathCallback callbackPointer); [STAThread] static void Main(string[] args) { // define a progress callback delegate ProgressCallback callback = (value) => { Console.WriteLine("Progress = {0}", value); }; Console.WriteLine("Press any key to run DoWork...."); Console.ReadKey(true); // call DoWork in C code DoWork(callback); Console.WriteLine(); Console.WriteLine("Press any key to run ProcessFile...."); Console.ReadKey(true); // define a get file path callback delegate GetFilePathCallback getPath = (filter) => { string path = default(string); OpenFileDialog ofd = new OpenFileDialog() { Filter = filter }; if (ofd.ShowDialog() == DialogResult.OK) { path = ofd.FileName; } return path; }; // call ProcessFile in C code ProcessFile(getPath); } }
如下附上本人編譯的代碼,和原文有點出入,主要是由於本人習慣用.NET 2.0,還有一些是爲了編譯期間順利經過編譯器。
代碼使用Visual Studio 2010+VC6.0編寫
下載地址:1.怎樣從C_C++代碼中對C#進行回調.rar