我正在尝试使用具有回调机制的(C)第三方库,该回调机制缺少识别调用上下文的任何可能方法。我的主要项目在C#中,包装器是一个用于调用C库API的C++/CLI项目。
要变通解决此问题,我试图使用Marshal::GetFUnctionPointerForDelegate。这是我的C#代码:
void Init(Handler Callback)
{
// Create a wrapper lambda in case Callback is a non-static method.
instance.CreateBuffers((x, y) => Callback(x, y));
}
然后,在C++/CLI代码中:
void CreateBuffers(Handler^ Callback)
{
pinCallback = GCHandle::Alloc(Callback);
void (*callback)(int, int) = (void (__stdcall *)(int, int))Marshal::GetFunctionPointerForDelegate(Callback).ToPointer(),
// Use 'callback' in third party library...
}
所有这一切的问题是,根据http://msdn.microsoft.com/en-us/library/367eeye0.aspx,来自Marshal::GetFunctionPointerForDelegate的函数指针是stdcall函数,但是我的C回调是cdecl。我如何在这里获得与cdecl兼容的功能?
最佳答案
我认为最简单的方法是使用UnmanagedFunctionPointer属性声明您的委托(delegate)类型为C#,以指定调用约定。
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate ...
然后,使您的C++/CLI代码接收纯本地C++函数指针。您可以传递委托(delegate)的实例,并且由于委托(delegate)具有该属性,因此编码员知道该怎么做。
这使您可以跳过GetFunctionPointerForDelegate步骤。实际上,它可以让您跳过C++/CLI层,但是我希望您不想这样做。
只要非托管代码可以看到函数指针,请确保托管代码保留对委托(delegate)的引用。如果您不这样做,那么垃圾收集器可能会将地毯从您下面拉下,因为它看不到非托管代码所拥有的引用。
当然,之前已经在此主题中进行过介绍。汉斯·帕桑特(Hans Passant)在这里有一个详细的答案,值得一读:Correct way to call a C DLL method from C#
关于c# - C#GetFunctionPointerForDelegate cdecl代替stdcall,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19740140/