2016-09-30 32 views
3
有叫它

我在C#以下設置:如何從C#傳遞一個委託或函數指針,C++和使用InternalCall

public delegate void CallbackDelegate(string message); 
[MethodImplAttribute(MethodImplOptions.InternalCall)] 
public static extern void setCallback(CallbackDelegate aCallback); 

public void testCallbacks() 
{ 
    System.Console.Write("Registering C# callback...\n"); 
    setCallback(callback01); 
} 

public void callback01(string message) 
{ 
    System.Console.Write("callback 01 called: " + message + "\n"); 
} 

而這在C++(該功能通過mono_add_internal_call正確註冊):

typedef void (*CallbackFunction)(const char*); 
void setCallback(MonoDelegate* delegate) 
{ 
    // How to convert the MonoDelegate to a proper function pointer? 
    // So that I can call it like func("test"); 
} 

的C++ - 函數被調用,東西傳遞給委託變量。 但現在呢?

我環顧四周,發現幾次提到的函數「mono_delegate_to_ftnptr」,從這些例子中,它似乎正是我所需要的。
但是,這個函數似乎並不存在於我的單聲道(4.6)發行版中,所以我只能猜測它不再存在。

我還發現了一些如何用PInvoke做到這一點的例子。這是我不想使用的 - 因爲InternalCall對於我的目的要快得多。
當然,如果PInvoke是唯一的方法,那就這樣吧,但我懷疑這一點。

最後,我對如何從這裏出發感到茫然。

+0

downvote的具體原因是什麼?我應該添加什麼? – TheSHEEEP

+0

在InternalCall,C++/CLI的Microsoft工具鏈實現中,您將使用簽名'setCallback(System :: Action ^delegate)'直接接受直接接收.NET的.NET代理串。也許如果你在Mono中展示瞭如何通過InternalCall函數傳遞.NET引用類型,它可能會導致更輕量級的解決方案。 –

回答

5

經過一段時間的挖掘,我終於找到了一個(?)解決方案。
基本上,PInvoke方法的工作原理也適用於這裏,您可以將函數指針而不是從C#委託給C(++)。
我更喜歡可以直接傳遞委託的解決方案,但是您可以在C#中添加一些包裝代碼,至少使它看起來像這樣。

解決方案:

C#:

public delegate void CallbackDelegate(string message); 
[MethodImplAttribute(MethodImplOptions.InternalCall)] 
public static extern void setCallback(IntPtr aCallback); 

private CallbackDelegate del; 
public void testCallbacks() 
{ 
    System.Console.Write("Registering C# callback...\n"); 
    del = new CallbackDelegate(callback01); 
    setCallback(Marshal.GetFunctionPointerForDelegate(del)); 

    System.Console.Write("Calling passed C++ callback...\n"); 
} 

public void callback01(string message) 
{ 
    System.Console.Write("callback 01 called. Message: " + message + "\n"); 
} 

C++:

typedef void (*CallbackFunction)(MonoString*); 
void setCallback(CallbackFunction delegate) 
{ 
    std::cout << &delegate << std::endl; 
    delegate(mono_string_new(mono_domain_get(), "Test string set in C++")); 
} 

小心,雖然:您需要在C#中以某種方式保持周圍委託(這就是爲什麼我將其分配給「del」),否則它將被GC捕獲,並且您的回調將失效。
當然,這很有道理,但我覺得在這種情況下很容易忘記。

+1

您可以刪除變量'name'來使示例更小。 –

+0

當然,爲什麼不呢。 :) – TheSHEEEP