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

问题描述:

在我的下一个项目中我想实现一个GUI已经存在的C ++代码。
我的计划是将C ++部分包装在DLL中并在C#中实现GUI。我的问题是,我不知道如何实现从非托管DLL的回调到Manged 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.

你不需要使用Marshal.GetFunctionPointerForDelegate marshaller自动。您需要在C#端声明一个委托,其签名与C ++端的函数指针声明兼容。例如:

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();
}

以及用于创建非托管DLL的相应C ++代码:

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");
}

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

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.