您的位置:首页 > 编程语言 > C语言/C++

How to make a callback to C# from C/C++ code

2013-06-30 08:18 555 查看


注:个人觉得这篇技术文章很有价值,收藏下,本来想翻译一下,最近有点懒,过两天再说。

http://www.codeproject.com/Tips/318140/How-to-make-a-callback-to-Csharp-from-C-Cplusplus

Almost
everyone knows how to make a call to a function in an unmanaged DLL. However, sometimes we wish that we could call C# code from C/C++ code.
Imagine a scenario wherein we have a C# application which has a native C DLL called Engine.dll.
There is a function entry named “
DoWork
” in this
DLL that we need to call. Calling 
DoWork
 in the
engine is as easy as making the following declaration in the C# code:

[DllImport("Engine.dll")]
public static extern void DoWork();

…and then using it like any other 
static
 C#
method in our C# application.
 
This will work just fine. However, let’s assume 
DoWork
 is
a long-running task and we want to show a progress or so in the C# app in order to keep our user(s) updated. To make this happen, we need to…

Define an unmanaged delegate in the C# code like –

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void ProgressCallback(int value);


Define callback signature in the C code –

typedef void (__stdcall * ProgressCallback)(int);


Change 
DoWork
 signature in C code to accept 
ProgressCallback
 address:

DLL void DoWork(ProgressCallback progressCallback)

Note: DLL is…

#define DLL __declspec(dllexport)


Inside the C# code, we need to create a delegate of type of the unmanaged delegate –

ProgressCallback callback =
(value) =>
{
Console.WriteLine("Progress = {0}", value);
};


Then for calling 
DoWork
, we need to do it like this –

DoWork(callback);


Here is a sample source code for a simple application. This code snippet includes a second scenario wherein we have a function in C code called 
ProcessFile
 that
needs to get back to the C# in order to obtain a file path for further processing - in this case, printing its contents to the console.
 
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);
}
}

 
Enjoy it 


License

This article, along with any associated source code and files, is licensed under The
Code Project Open License (CPOL)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ C#