调用C#中包含回调的C++函数

本文关键字:C++ 函数 回调 包含 调用 | 更新日期: 2023-09-27 18:27:38

嘿,我正试图在c#中调用这个c++函数:

BOOL __stdcall CodecStart(int hRadio,void __stdcall (*CallbackFunc)(void *),void *CallbackTarget);

这是来自此处的WinRadio apihttp://www.winradio.com/home/g305_sdk.htm.

我确实发现其他人询问过在网上调用这个特定的函数,他们得到了:

    public delegate void CallbackFunc( IntPtr p);
    [DllImport("WRG305API.dll")]
    public static extern bool CodecStart(int hRadio, CallbackFunc func, IntPtr CallbackTarget);

但我不知道如何进一步实现这一点。

关于如何称呼这件事,有什么想法或指导吗?

非常感谢

调用C#中包含回调的C++函数

这里有一个简单的实现,它将把所有这些放在一起。

class WinRadioWrapper
{
    public delegate void CallbackFunc( IntPtr pData );
    [DllImport( "WRG305API.dll" )]
    public static extern bool CodecStart( int hRadio, CallbackFunc func, IntPtr CallbackTarget );
    public bool CodecStartTest(int hRadio)
    {
        bool bStarted = CodecStart( hRadio, MyCallbackFunc, IntPtr.Zero );
        return bStarted;
    }
    // Note: this method will be called from a different thread!
    static void MyCallbackFunc( IntPtr pData )
    {
        // Sophisticated work goes here...
    }
}
  • 注意,因为MyCallbackFunc将在不同的线程上执行,所以我选择将其设为static。这样,您就不会想访问WinRadioWrapper数据成员。

  • 为了简单起见,我向回调传递了一个IntPtr.Zero参数,但这可以指向您想在回调中使用的任何数据

    [请忽略此段落]如果您想将数据传递给回调,请查看Marshal.StructureToPtr,但也要固定您正在传递的数据,以确保它不会被垃圾收集(有关更多详细信息,请参阅GCHandle

编辑:
有了svick有趣的话(谢谢!),我意识到我把复制的东西和固定的东西混合在一起了。
所以,为了解决问题:

  • 如果要复制现有的数据结构,然后将其传递给回调函数,则应使用Marshal.StructureToPtr
  • 另一方面,如果您想使用和现有的数据结构(例如,用于修改其内容),则应使用GCHandle,以便固定在内存中,并防止其被垃圾收集
    但是,这将增加GCHandle的一些维护开销

回调函数是由执行某些函数的dll(在本例中是导入的)调用的代码。您还需要学习如何在c#中使用委托。你可以实现这样的代码:

public void MyCallback(IntPtr p)
{
    //do something
}

然后你的dll调用会是这样的:

[DllImport("WRG305API.dll")]
    public static extern bool CodecStart(int hRadio, func, IntPtr CallbackTarget);

如果您需要更多指导,请发布您想要转换的代码的C++版本,我们可以帮助您使用C#版本。

您所需要做的就是创建一个与您声明的委托的签名匹配的c#函数。创建一个委托,保留对此委托的引用,这样它就不会被垃圾收集,并将该委托作为回调调用dll导入。

所以你会有这样的东西:

public void MyCallback(IntPtr P)
{
    //do something
}
// somewhere else in your code
var cb = new CallbackFunc(MyCallback);
CodecStart(..., cb, ...);