[翻譯]:怎樣從C/C++代碼中對C#進行回調

聲明:網絡上相似的中文博客大有存在,本人知識水平有限,業餘愛好,也是爲了備份收藏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

            2.怎樣從C_Cpp代碼中對CSharp進行回調2.rar

相關文章
相關標籤/搜索