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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将委托或函数指针从C#传递给C ++并使用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...
");
    setCallback(callback01);
}

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

这在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...
");
    del = new CallbackDelegate(callback01);
    setCallback(Marshal.GetFunctionPointerForDelegate(del));

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

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

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#传递给C ++并使用InternalCall在那里调用它的主要内容,如果未能解决你的问题,请参考以下文章

如何将委托或函数指针从 C# 传递到 C++ 并使用 InternalCall 调用它

如何将 C++ 回调传递给 C 库函数?

如何正确地将浮点指针从 C 库传递到其 C# 包装器

如何使用 Python C/C++ 接口将实例成员函数作为 PyCFunction 类型传递

如何将函数作为参数从 C 传递到 C++ 并返回到 C

如何通过c中的指针传递二维数组[重复]