简体   繁体   English

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

[英]Howto implement callback interface from unmanaged DLL to .net app?

in my next project I want to implement a GUI for already existing code in C++. 在我的下一个项目中,我想为C ++中已经存在的代码实现GUI。 My plan is to wrap the C++ part in a DLL and to implement the GUI in C#. 我的计划是将C ++部分包装在DLL中,并在C#中实现GUI。 My problem is that I don't know how to implement a callback from the unmanaged DLL into the manged C# code. 我的问题是我不知道如何实现从非托管DLL到托管C#代码的回调。 I've already done some development in C# but the interfacing between managed and unmanaged code is new to me. 我已经用C#进行了一些开发,但是托管代码和非托管代码之间的接口对我来说是新的。 Can anybody give me some hints or reading tips or a simple example to start from? 任何人都可以给我一些提示或阅读提示或一个简单的示例作为开始吗? Unfortunatly I could not find anything helpful. 不幸的是,我找不到任何帮助。

You don't need to use Marshal.GetFunctionPointerForDelegate(), the P/Invoke marshaller does it automatically. 您不需要使用Marshal.GetFunctionPointerForDelegate(),P / Invoke编组器会自动执行此操作。 You'll need to declare a delegate on the C# side whose signature is compatible with the function pointer declaration on the C++ side. 您需要在C#端声明一个委托,该委托的签名与C ++端的函数指针声明兼容。 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: 以及用于创建非托管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. 使这种代码运行的更有效的方法是用C ++ / CLI语言编写包装器。 That also lets you wrap a C++ class, something you can't do with P/Invoke. 这也使您可以包装C ++类,而P / Invoke无法做到这一点。 A decent tutorial is available here. 此处提供了不错的教程

P/Invoke can handle marshaling a managed delegate to a function pointer. P / Invoke可以处理将托管委托编组到函数指针。 So if you expose API's that register a call back function from your DLL and in C# pass a delegate to that function. 因此,如果您公开从DLL注册了回调函数的API,并在C#中将委托传递给该函数。

There is an example on MSDN of doing this with the EnumWindows function. MSDN上有一个使用EnumWindows函数执行此操作的示例。 In that article be careful to pay attention to the line in point 4 that states: 在该文章中,请注意第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. 有关防止垃圾收集的详细信息,请参阅使用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. 这就是说,您需要通过在代码中保留对它的引用或将其固定来确保在托管代码调用完委托之前,不对您的委托进行垃圾回收。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM