如何将委托或函数指针从 C# 传递到 C++ 并使用 InternalCall 调用它
How to pass a delegate or function pointer from C# to C++ and call it there using InternalCall
我在 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 是唯一的方法,那就这样吧,但我对此表示怀疑。
最后,我真的不知道如何从这里开始。
经过几个小时的挖掘,我终于找到了(那个?)解决方案。
基本上,适用于 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));
}
我在 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 是唯一的方法,那就这样吧,但我对此表示怀疑。
最后,我真的不知道如何从这里开始。
经过几个小时的挖掘,我终于找到了(那个?)解决方案。
基本上,适用于 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
.
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));
}