如何实现从非托管DLL到.net应用程序的回调接口?

发布于 2024-08-19 21:00:38 字数 194 浏览 8 评论 0原文

在我的下一个项目中,我想为 C++ 中已有的代码实现一个 GUI。 我的计划是将 C++ 部分包装在 DLL 中,并用 C# 实现 GUI。我的问题是我不知道如何实现从非托管 DLL 到托管 C# 代码的回调。我已经在 C# 中完成了一些开发,但托管代码和非托管代码之间的接口对我来说是新的。有人可以给我一些提示或阅读技巧或一个简单的例子吗?不幸的是我找不到任何有用的东西。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

电影里的梦 2024-08-26 21:00:38

您不需要使用 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();
}

以及用于创建非托管 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 无法做到的。 此处提供了一个不错的教程。

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:

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:

#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.

ゞ花落谁相伴 2024-08-26 21:00:38

P/Invoke 可以处理将托管委托编组到函数指针的情况。因此,如果您公开从 DLL 注册回调函数的 API,并在 C# 中将委托传递给该函数。

MSDN 上有一个执行此操作的示例使用 EnumWindows 函数。在那篇文章中,请注意第 4 点中的内容:

但是,如果回调函数可以
调用返回后被调用,
受管理的呼叫者必须采取措施
确保代表继续留任
直到回调才被收集
函数结束。如需详细
关于防止垃圾的信息
集合,请参阅互操作封送处理
与平台调用。

这就是说,您需要确保您的委托在托管代码完成调用它之前不会被垃圾收集,方法是在代码中保留对它的引用或固定它。

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.

There is an example on MSDN of doing this with the EnumWindows function. In that article be careful to pay attention to the line in point 4 that states:

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.

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.

你另情深 2024-08-26 21:00:38

请参阅 Marshal.GetFunctionPointerForDelegate,其中将为您提供一个函数指针,用于从非托管代码调用托管(即 C# 代码)。

See Marshal.GetFunctionPointerForDelegate, which will give you a function pointer for calling managed (i.e. C# code) from unmanaged code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文