7

我正在尝试使用具有回调机制的(C)第三方库,该回调机制缺乏任何可能的方式来识别调用上下文。我的主要项目是 C#,我的包装器是一个 C++/CLI 项目,用于调用 C 库 API。

为了解决这个问题,我尝试使用 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 兼容的功能?

4

1 回答 1

7

I think that the simpest way to achieve this is to declare your delegate type is C# with the UnmanagedFunctionPointer attribute to specify the calling convention.

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate ...

Then make your C++/CLI code receive a plain native C++ function pointer. You can pass an instance of your delegate, and because the delegate has that attribute, the marshaller knows what to do.

This allows you to skip the GetFunctionPointerForDelegate step. In fact it would allow you to skip right over the C++/CLI layer, but I expect that you don't want to do that.

Make sure that your managed code retains a reference to the delegate for as long as the unmanaged code can see the function pointer. If you don't do so then the garbage collector may pull the rug from under you since it cannot see the reference held by the unmanaged code.

This topic has been covered here before, of course. Hans Passant has a detailed answer here that is worth reading: Correct way to call a C DLL method from C#

于 2013-11-02T08:37:55.220 回答