2010-01-30 77 views
18

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

回答

42

您不需要使用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无法做到的。一个体面的教程是available here.

+0

谢谢nobugz,我会尽快尝试。我希望我不会陷入太多麻烦;-) – chrmue 2010-01-30 18:04:51

+0

完美地为我工作,再次感谢! – chrmue 2010-02-15 13:39:01

5

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

MSDN上有一个关于EnumWindows函数的例子。在这篇文章中要小心,要注意第4点,指出行:

然而,如果回调函数可以 可以在调用返回后调用时, 托管调用方必须采取措施,以 保证该代表仍保持 未收集,直到回调函数 完成。有关详细信息 有关防止垃圾收集的信息,请参阅Interop Marshaling 及平台调用。

那是什么要说的是,你需要确保你的委托是没有收集到后,托管代码由要么保持在你的代码对它的引用,或牵制它做叫它垃圾。

+0

+1对于批判 - 单独使用P/Invoke只能保证指针在调用期间的有效性 - 如果你正在缓存它,你需要钉住它(不能说存储引用,可疑,但这并不意味着:-) – 2013-01-08 21:28:11

相关问题