如何将委托或函数指针从c#传递到c++,并使用InternalCall在那里调用它

本文关键字:c++ 调用 在那里 InternalCall 函数 指针 | 更新日期: 2023-09-27 18:09:44

我在c#中有以下设置:

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"提到了几次,从这些例子中,它似乎正是我需要的。
然而,这个函数在我的mono(4.6)发行版中似乎根本不存在,所以我只能猜测它不再存在了。

我还找到了一些如何使用PInvoke实现这一点的示例。这是我不想使用的东西-因为InternalCall对我的目的要快得多。
当然,如果PInvoke是唯一的方法,那就这样吧,但我对此表示怀疑。

最后,我真的不知道如何从这里开始。

如何将委托或函数指针从c#传递到c++,并使用InternalCall在那里调用它

经过几个小时的挖掘,我终于找到了一个解决方案。
基本上,适用于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捕获,并且你的回调将无效。
当然,这是有道理的,但我觉得在这种情况下,这很容易被忘记。

您可以使用intptr_t将c++中的函数指针作为参数传递给c#。

MSDN不准确,下面的代码可以工作:

在c++

:

static void func(int param)
{
    //...
}  
    
void other_func()
{
    ptr->SetCallback( reinterpret_cast<intptr_t>(func));
}
在c#

:

public static mydelegatetype somefunc = null;
    
public void SetCallback(IntPtr function_pointer)
{
    somefunc = (mydelegatetype)
    Marshal.GetDelegateForFunctionPointer(function_pointer, typeof(mydelegatetype));
}