2010-01-30 79 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

相關問題