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

时间:2012-03-11 22:01:17

标签: c# c++ api callback dllimport

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

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

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

我确实发现其他人询问在网上调用这个特定的功能,他们有:

    public delegate void CallbackFunc( IntPtr p);

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

但我无法弄清楚如何进一步实现这一点。

关于如何称呼它的任何想法或指导?

非常感谢

3 个答案:

答案 0 :(得分:4)

这是一个简单的实现,将它们放在一起。

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将在不同的线程上执行,所以我选择make static。这样,您就不会想要访问WinRadioWrapper数据成员。

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

    [请忽略此段] 如果您想将数据传递给回调,请查看Marshal.StructureToPtr,但请确保固定您所拥有的数据重新传递,以确保它不被垃圾收集(有关详细信息,请参阅GCHandle)。

修改
svick的有趣词语(谢谢!),我意识到我正在混合一个复制的对象和一个固定的对象。
所以,要解决问题:

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

答案 1 :(得分:0)

callback function是由执行某些功能的dll(在这种情况下,您正在导入)调用的代码。您还需要了解如何使用delegates in c#。您可以像这样实现代码:

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

然后你的dll电话会是这样的:

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

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

答案 2 :(得分:0)

您需要做的就是创建一个与您声明的委托的签名相匹配的c#函数。创建一个委托,保持对该委托的引用,使其不被垃圾收集,并以委托作为回调调用dll导入。

所以你会有这样的事情:

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

// somewhere else in your code
var cb = new CallbackFunc(MyCallback);
CodecStart(..., cb, ...);