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

时间:2010-01-30 12:46:43

标签: c# c++ callback unmanaged managed

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

4 个答案:

答案 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)