【发布时间】:2019-01-25 07:51:09
【问题描述】:
我有一个如下所示的 C# 方法:
public delegate void VariableObserver(string variableName, object newValue);
public void ObserveVariable(string variableName, VariableObserver observer)
{
// stuff
}
此代码嵌入到 C++ 应用程序中,我想从 C++ 调用 ObserveVariable 函数,传递函数指针或与 VariableObserver 委托等效的东西。这样做的目的是让 C# 代码可以调用委托,然后调用 C++ 函数。
我习惯于使用mono_runtime_invoke 来调用C# 函数,而且效果很好。但是,我找不到任何有用的文档示例来说明如何传递函数指针/委托。您是否需要像使用字符串等某些类型一样将其装箱?如果是这样,你如何做到这一点?有可能吗?
我在四处搜索时发现了 Marshal.GetDelegateFromFunctionPointer 方法,我想我可以在 C# 中使用它来获取 delgate 并照常进行,但是 these docs 说它现在已经过时了。
编辑:我发现了更多的东西。有这个较新的 Marshal 函数:Marshal.GetDelegateForFunctionPointer<TDelegate>(IntPtr),看起来很有希望,但它明确表示“您不能将此方法与通过 C++ 或 GetFunctionPointer 方法获得的函数指针一起使用。” :(
Edit2:我尝试过仅使用 GetDelegateForFunctionPointer 的建议,但看起来函数指针的编组不正确。看看:
C#代码:
delegate void TestObserver(int num);
public void BindObserver(IntPtr observerFuncPtr)
{
TestObserver obs = Marshal.GetDelegateForFunctionPointer<TestObserver>(observerFuncPtr);
obs(1337);
}
C++ 代码:
static void ObserverCallback(int num)
{
printf("WE GOT A CALLBACK %d", num);
}
// inside a function I call
void* params[1];
params[0] = &ObserverCallback;
MonoObject* exception;
mono_runtime_invoke(theMonoMethod, theMonoInstance, params, &exception);
但是这样做会导致 C# 出现此错误:
Runtime Exception : System.NullReferenceException: Object reference not set to an instance of an object
at (wrapper managed-to-native) System.Object:wrapper_native_8348575608244C89 (int)
at InkGlue.GlueStory.BindObserver (System.IntPtr observerFuncPtr) [0x00006] in <78fcd644f8db43978f6f7b1655d0ab2f>:0
这让我相信函数指针没有成功传递给 C#。有关如何正确执行此操作的任何信息?
【问题讨论】:
-
尝试将
extern “C”添加到 ObserverCallback 的声明中,以确保它遵循 C 调用约定。 -
您可能还需要在委托声明中使用
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]。 -
&ObserverCallback 不是正确的函数指针。您缺少函数指针类型 - 请参阅:stackoverflow.com/questions/2298242/callback-functions-in-c