声明:网络上类似的中文博客大有存在,本人知识水平有限,业余爱好,也是为了备份收藏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#代码中做以下声明一样简单。

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

这段代码运行将非常良好,然而,让我再假设一下DoWork是一个连续性运行的任务,为了保证我们的用户端可被更新,
我们希望显示一个进度。想要实现这一点,我们需要做出以下几步:

1.在C#代码中定义一个类似的非托管代码委托

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

2.在C代码中定义一个回调签名

typedef void (__stdcall * ProgressCallback)(int);

3.在C代码中更改DoWork的签名以便接收ProgressCallback的地址

DLL void DoWork(ProgressCallback progressCallback)

注意:DLL宏的声明是这样的

#define DLL __declspec(dllexport)

4.在C#代码中,我们需要创建一个非托管委托类型的委托

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 = ; for(; counter<=; 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[]; // print file info to the screen
printf("File path: %s\n", path ? path : "N/A");
printf("File content:\n"); while(fgets(line, , 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

[翻译]:怎样从C/C++代码中对C#进行回调的更多相关文章

  1. 检查.net代码中占用高内存函数(翻译)

    哈哈,昨天没事做,在CodeProject瞎逛,偶然看到这篇文章,居然读得懂,于是就翻译了一下,当练习英语,同时增强对文章的理解,发现再次翻译对于文章的一些细节问题又有更好的理解.下面是翻译内容,虽然 ...

  2. 在后台代码中动态生成pivot项并设置EventTrigger和Action的绑定

    最近在做今日头条WP的过程中,遇到需要动态生成Pivot项的问题.第一个版本是把几个频道写死在xaml里了,事件绑定也写在xaml里,每个频道绑定一个ObservableCollection<A ...

  3. 要心中有“数”——C语言初学者代码中的常见错误与瑕疵(8)

    在 C语言初学者代码中的常见错误与瑕疵(7) 中,我给出的重构代码中存在BUG.这个BUG是在飞鸟_Asuka网友指出“是不是时间复杂度比较大”,并说他“第一眼看到我就想把它当成一个数学问题来做”之后 ...

  4. 【Win 10 应用开发】在代码中加载文本资源

    记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...

  5. Salesforce 自定义标签在代码中的应用

    自定义标签简介 Salesforce 中自定义标签(Custom Label)的作用是存储一般性的文本,可以用于 Apex.Visualforce 页面.Lightning 组件等地方,用于显示提示信 ...

  6. [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置

    [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置 原文: USING CONSUL FOR STORING THE CONFIGURATION IN ASP.NET COR ...

  7. 18.翻译系列:EF 6 Code-First 中的Seed Data(种子数据或原始测试数据)【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/seed-database-in-code-first.aspx EF 6 Code-F ...

  8. 11.翻译系列:在EF 6中配置一对零或者一对一的关系【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-fi ...

  9. 【翻译】TCP backlog在Linux中的工作原理

    原文How TCP backlog works in Linux水平有限,难免有错,欢迎指出!以下为翻译: 当应用程序通过系统调用listen将一个套接字(socket)置为LISTEN状态时,需要为 ...

随机推荐

  1. 20条Linux命令面试问答

    程序师  http://www.techug.com/20-linux-command-interview-questions 问:1 如何查看当前的Linux服务器的运行级别? 答: ‘who -r ...

  2. linux 进程的创建

    1. 进程号: 每个进程在被初始化的时候,系统都会为其分配一个唯一标识的进程id,称为进程号: 进程号的类型为pid_t,通过getpid()和getppid()可以获取当前进程号和当前进程的父进程的 ...

  3. JS获取IMG图片高宽

    前段时间在LJW写的touchslider.js轮播代码里添加自适应屏幕大小的功能时,遇到一个问题.不管用什么样的方法都无法获取到IMG标签的高宽,最后只有给图片定一个高宽的比例值:趁今天有空我就写了 ...

  4. 在xilinxFPGA上使用microblaze及自写GPIO中断

    很久很久没有更新过博客了,今天来扒一扒FPGA上CPU软核的使用. 主要完成的功能:使用的开发板是nexys 4 DDR,板上有16个switch以及16个LED,需要完成microblaze对led ...

  5. mysql 忘记root 密码的解决方法

    LINUX 1.切换root 用户 2.停止mysqld 服务 /etc/inid.d mysqld stop 3.跳过验证登录 mysqld_safe --skip-grant-tables &am ...

  6. 转 Jmeter之Bean shell使用(二)

    上一篇Jmeter之Bean shell使用(一)简单介绍了下Jmeter中的Bean shell,本文是对上文的一个补充,主要总结下常用的几种场景和方法,相信这些基本可以涵盖大部分的需求.本节内容如 ...

  7. ASP.NET Misconfiguration: Excessive Session Timeout

    Abstract: An overly long authentication timeout gives attackers more time to potentially compromise ...

  8. [delphi]极域学生端解除键盘鼠标锁定退出全屏广播-强制窗口化-源代码

    v2.0  2015-07-11 更新了V2.0 版本 发布在吾爱破解论坛 欢迎下载使用 http://www.52pojie.cn/thread-382769-1-1.html ---------- ...

  9. 博客代码:iframe—网页中嵌入其他网页

    iframe 是一个可以把另外一个网页嵌入到一个网页里的代码,非常有用.对于一个内容不错的网页,要方便地把它搬到自己的博客里,用这个代码最合适.而对于在新浪博客里不支持的一些网页效果和代码,可先把他们 ...

  10. [AS3]as3画笔实例实现橡皮擦功能源代码

    [AS3]as3画笔实例实现橡皮擦功能源代码 //主容器 var main:Sprite = new Sprite(); main.mouseEnabled = false; addChild(mai ...