繁体   English   中英

在C#中使用C ++回调接口

[英]Using a C++ callback interface in C#

我正在编写一个需要使用DirectShow录制视频的应用程序-为此,我正在使用Interop库DirectShowLib,它看起来很棒。

但是,由于样本已写入文件中,因此现在我需要获取回调通知,因此可以添加数据单元扩展。 根据msdn文档,在C ++中,这是通过实现IAMWMBufferPassCallback接口并将结果对象传递到引脚的IAMWMBufferPass接口的SetNotify方法来完成的。

因此,我创建了一个小类,该类从DirectShowLib实现IAMWMBufferPassCallback接口:

 class IAMWMBufferPassCallbackImpl : IAMWMBufferPassCallback    
 {  
        private RecordingPlayer player;

        public IAMWMBufferPassCallbackImpl(RecordingPlayer player)
        {
            this.player = player;
        }

        public int Notify(INSSBuffer3 pNSSBuffer3, IPin pPin, long prtStart, long prtEnd)
        {
            if (player.bufferPin == pPin && !player.firstBufferHandled)
            {
                player.firstBufferHandled = true;

                //do stuff with the buffer....
            }

            return 0;
        }

}

然后,我检索了所需引脚的IAMWMBufferPass接口,并将该类的实例传递给SetNotify方法:

bufferPassCallbackInterface = new IAMWMBufferPassCallbackImpl(this);

IAMWMBufferPass bPass = (IAMWMBufferPass)DSHelper.GetPin(pWMASFWriter, "Video Input 01");

hr = bPass.SetNotify(bufferPassCallbackInterface);
DsError.ThrowExceptionForHR(hr);  

没有引发异常,表明SetNotify方法成功。

现在的问题是,我的回调对象中的Notify方法永远不会被调用。 该视频记录没有问题,只是回调根本没有执行。

我做互操作的方式有问题吗?

我通常与不安全的C#代码中的函数指针的委托一起工作。
唯一的技巧是,您需要确保不会对该委托的引用进行垃圾收集,因为在对垃圾收集器中的引用进行计数时,将不使用不安全代码中的引用。 因此,该功能要么需要是静态的,要么是持有引用的对象需要附加的人工引用以确保其可用性。
这是在MSDN上使用委托教程

您进行互操作的方式看起来很好。 我看了看MSDN文档,看起来您也朝着正确的方向前进,所以我不知道为什么它不进行回调。

但是,一旦完成回调,您可能需要确保调用Marshal.ReleaseComObject(pNSSBuffer3)。 有时,直到所有其他引用都被删除后,样本缓冲区才会释放出来进行处理。 SampleGrabber就是这种情况,因此可能与此相同。

您可能应该使用委托:

delegate int NotifyDelegate(INSSBuffer3 pNSSBuffer3, IPin pPin, long prtStart, long prtEnd);

void run(){
  bufferPassCallbackInterface = new IAMWMBufferPassCallbackImpl(this);

  IAMWMBufferPass bPass = (IAMWMBufferPass)DSHelper.GetPin(pWMASFWriter, "Video Input 01");
  NotifyDelegate d = new NotifyDelegate(bufferPassCallbackInterface.Notify);

  hr = bPass.SetNotify(d);
  DsError.ThrowExceptionForHR(hr);  
}

但是,我不太确定如何在托管类上实现非托管接口。 C ++中的INSSBuffer3 *与C#中的新INNSBuffer3()不直接相关。

编辑:

为了回应您的评论,SetNotify函数定义为

HRESULT SetNotify(
  [in]  IAMWMBufferPassCallback *pCallback
);

因此,它需要一个指向IAMWMBufferPassCallback的实现的指针。

MSDN说pCallback是pCallback a

指向应用程序的IAMWMBufferPassCallback接口的指针。

委托是(试图成为)托管的等效于IAMWMBufferPassCallback的指针。 回调通常是一种方法,而不是对象。 因此,传递委托的实例将为您工作。 另一个类似的示例是InternetSetStatusCallback ,您可以在其中传递指向InternetStatusCallback的实现的指针。

我会尝试一下,如果它不起作用,为什么不尝试一个已经有人完成所有辛苦工作的图书馆呢? DirectShowNet可能是一个选项(我从未使用过)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM