C# 如何实现从非托管 DLL 到 .net 应用程序的回调接口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2167895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Howto implement callback interface from unmanaged DLL to .net app?
提问by chrmue
in my next project I want to implement a GUI for already existing code in C++. My plan is to wrap the C++ part in a DLL and to implement the GUI in C#. My problem is that I don't know how to implement a callback from the unmanaged DLL into the manged C# code. I've already done some development in C# but the interfacing between managed and unmanaged code is new to me. Can anybody give me some hints or reading tips or a simple example to start from? Unfortunatly I could not find anything helpful.
在我的下一个项目中,我想为 C++ 中的现有代码实现一个 GUI。我的计划是将 C++ 部分包装在 DLL 中,并在 C# 中实现 GUI。我的问题是我不知道如何实现从非托管 DLL 到托管 C# 代码的回调。我已经在 C# 中进行了一些开发,但是托管和非托管代码之间的接口对我来说是新的。任何人都可以给我一些提示或阅读技巧或一个简单的例子吗?不幸的是,我找不到任何有用的东西。
采纳答案by Hans Passant
You don't need to use Marshal.GetFunctionPointerForDelegate(), the P/Invoke marshaller does it automatically. You'll need to declare a delegate on the C# side whose signature is compatible with the function pointer declaration on the C++ side. For example:
您不需要使用 Marshal.GetFunctionPointerForDelegate(),P/Invoke 编组器会自动执行此操作。您需要在 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();
}
And the corresponding C++ code used to create the unmanaged DLL:
以及用于创建非托管 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");
}
That's enough to get you started with it. There are a million details that can get you into trouble, you are bound to run into some of them. The much more productive way to get this kind of code going is writing a wrapper in the C++/CLI language. That also lets you wrap a C++ class, something you can't do with P/Invoke. A decent tutorial is available here.
这足以让您开始使用它。有一百万个细节会让你陷入困境,你一定会遇到其中的一些。使用 C++/CLI 语言编写包装器是让此类代码运行的更高效的方法。这也让您可以包装 C++ 类,这是 P/Invoke 无法做到的。这里有一个不错的教程。
回答by t0mm13b
Have a look at this, Marshal.GetDelegateForFunctionPointer?
回答by H?vard S
See Marshal.GetFunctionPointerForDelegate, which will give you a function pointer for calling managed (i.e. C# code) from unmanaged code.
请参阅Marshal.GetFunctionPointerForDelegate,它将为您提供一个函数指针,用于从非托管代码调用托管(即 C# 代码)。
回答by shf301
P/Invoke can handle marshaling a managed delegate to a function pointer. So if you expose API's that register a call back function from your DLL and in C# pass a delegate to that function.
P/Invoke 可以处理将托管委托编组到函数指针的问题。因此,如果您公开从 DLL 注册回调函数的 API,并在 C# 中将委托传递给该函数。
There is an example on MSDNof doing this with the EnumWindows function. In that article be careful to pay attention to the line in point 4 that states:
MSDN上有一个使用 EnumWindows 函数执行此操作的示例。在那篇文章中,请注意第 4 点中的这一行:
If, however, the callback function can be invoked after the call returns, the managed caller must take steps to ensure that the delegate remains uncollected until the callback function finishes. For detailed information about preventing garbage collection, see Interop Marshaling with Platform Invoke.
但是,如果可以在调用返回后调用回调函数,则托管调用方必须采取措施确保委托在回调函数完成之前保持未被收集。有关防止垃圾回收的详细信息,请参阅 Interop Marshaling with Platform Invoke。
What that is saying is that you need to make sure that your delegate isn't garbage collected until after the managed code is done calling it by either keeping a reference to it in your code, or pinning it.
这就是说,您需要确保您的委托在托管代码完成调用之前不会被垃圾收集,方法是在代码中保留对它的引用或固定它。