在我的下一个项目中,我想为C ++中已有的代码实现GUI。 我的计划是将C ++部分包装在DLL中并在C#中实现GUI。我的问题是我不知道如何实现从非托管DLL到manged C#代码的回调。我已经在C#中做了一些开发,但是托管和非托管代码之间的接口对我来说是新的。任何人都可以给我一些提示或阅读提示或一个简单的例子来开始吗?不幸的是,我找不到任何有用的东西。
答案 0 :(得分:49)
您不需要使用Marshal.GetFunctionPointerForDelegate(),P / Invoke marshaller会自动执行。您需要在C#端声明一个委托,其签名与C ++端的函数指针声明兼容。例如:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
class UnManagedInterop {
private delegate int Callback(string text);
private Callback mInstance; // Ensure it doesn't get garbage collected
public UnManagedInterop() {
mInstance = new Callback(Handler);
SetCallback(mInstance);
}
public void Test() {
TestCallback();
}
private int Handler(string text) {
// Do something...
Console.WriteLine(text);
return 42;
}
[DllImport("cpptemp1.dll")]
private static extern void SetCallback(Callback fn);
[DllImport("cpptemp1.dll")]
private static extern void TestCallback();
}
用于创建非托管DLL的相应C ++代码:
#include "stdafx.h"
typedef int (__stdcall * Callback)(const char* text);
Callback Handler = 0;
extern "C" __declspec(dllexport)
void __stdcall SetCallback(Callback handler) {
Handler = handler;
}
extern "C" __declspec(dllexport)
void __stdcall TestCallback() {
int retval = Handler("hello world");
}
这足以让你开始使用它。有一百万个细节可以让你遇到麻烦,你一定会碰到其中的一些。获得此类代码的更有效方法是使用C ++ / CLI语言编写包装器。这也允许你包装一个C ++类,这是P / Invoke无法做到的。一个体面的教程是available here.
答案 1 :(得分:6)
P / Invoke可以处理将托管委托封送到函数指针。因此,如果您公开从您的DLL注册回调函数的API,并在C#中将委托传递给该函数。
在MSDN上有一个使用EnumWindows函数执行此操作的示例。在那篇文章中要注意注意第4点中的一行:
但是,如果回调函数可以 在调用返回后调用, 托管调用者必须采取措施 确保代表仍然存在 直到回调才收集 功能完成。详细说明 有关防止垃圾的信息 收集,请参阅Interop Marshaling 使用平台调用。
这就是说,您需要确保您的委托不是垃圾收集,直到托管代码完成后调用它,方法是在代码中保留对它的引用,或者固定它。
答案 2 :(得分:1)
参见Marshal.GetFunctionPointerForDelegate,它将为您提供一个函数指针,用于从非托管代码中调用托管(即C#代码)。
答案 3 :(得分:0)