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

chr*_*mue 23 c# c++ unmanaged managed callback

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

Han*_*ant 50

你不需要使用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();
}
Run Code Online (Sandbox Code Playgroud)

以及用于创建非托管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");
}
Run Code Online (Sandbox Code Playgroud)

这足以让你开始使用它.有一百万个细节可以让你遇到麻烦,你一定会碰到其中一些.获得此类代码的更有效方法是使用C++/CLI语言编写包装器.这也允许你包装一个C++类,这是P/Invoke无法做到的.这里有一个体面的教程.


shf*_*301 6

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

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

但是,如果在调用返回后可以调用回调函数,则托管调用者必须采取措施以确保在回调函数完成之前代理保持未收集状态.有关防止垃圾回收的详细信息,请参阅使用平台调用进行Interop Marshaling.

这就是说,您需要确保您的委托不是垃圾收集,直到托管代码完成调用后,通过在代码中保留对它的引用或固定它.