QueryInterface在C#上使用E_NOINTERFACE失败

时间:2013-03-27 06:56:22

标签: c# visual-studio-2008 camera directshow

Hi Stack Overflow成员,

我是C#编程的新手。我正在开发基本的相机流媒体并仍然捕捉应用程序。一旦用户静止不动,我将使用VMR9的位图混合概念在叠加层上显示它。

我做了什么?

  • 我正在使用here
  • 中的C#direct show library
  • 首先,我获得所有必需的过滤器接口。找到附加的捕获设备。称为具有源过滤器的渲染流和用于PREVIEW引脚的vmr9。 STILL PIN的源过滤器,样本抓取器和空渲染器。
  • 我有三个菜单按钮 - >采取静止,显示叠加和隐藏叠加。
  • 我正在使用该库中提供的位图混合器示例。
  • 每次用户按下Take Still菜单时,图像将保存在桌面上,并将重新调整为小分辨率并显示在视频叠加上。
  • 显示叠加并隐藏叠加调用ShowHideBitmap()执行从vmr9过滤器查询VMR9BitmapMixer接口的操作,填充VMR9AlphaBitmap结构,然后调用IVMRMixerBitmap9.SetAlphaBitmap函数。

我面临什么问题?

  • 拍摄静止后,如果我通过菜单选项调用ShowHideBitmap(),则会在叠加时完美更新拍摄的静止图像。
  • 这是保存静止图像时立即执行叠加自动更新的另一个选项。我创建基于事件的线程,并使其等待使用EventWaitHandle创建的更新事件。在从samplegrabber BufferCB函数返回之前,我设置了此更新事件。这反过来继续等待线程。在内部线程我调用ShowHideBitmap函数。在这种情况下,我收到如下错误消息。

Unable to case COM object of type 'DirectShowLib.VideoMixingRenderer9' to interface type 'DirectShowLib.IVMRMixerBitmap9'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{ced175e5-1935-4820-81bd-ff6ad00c9108}' failed due to the following error: No such interface supported (Exception from HRESULT: 0X80040002 (E_NOINTERFACE)

这是ShowHideBitmap函数的代码块

//Declarations
private static IBaseFilter vmr9 = null;
private static IVMRMixerBitmap9 vmr9mixerBitmap = null;
private IVMRWindowlessControl9 vmr9windowlessCtrl = null;

private static void ShowHideBitmap(Boolean bEnable)
{
int hr = 0;
VMR9AlphaBitmap alphaBmp;

if (!bEnable)
{
    if (vmr9mixerBitmap != null)
    {
        // Get current Alpha Bitmap Parameters
        hr = vmr9mixerBitmap.GetAlphaBitmapParameters(out alphaBmp);
        DsError.ThrowExceptionForHR(hr);

        // Disable them
        alphaBmp.dwFlags = VMR9AlphaBitmapFlags.Disable;

        // Update the Alpha Bitmap Parameters
        hr = vmr9mixerBitmap.UpdateAlphaBitmapParameters(ref alphaBmp);
        DsError.ThrowExceptionForHR(hr);

        // Create a surface from our alpha bitmap
        surface.Dispose();

        vmr9mixerBitmap = null;

        //Release this alpha bitmap source.
        if (alphaBitmap != null)
        {
            alphaBitmap.Dispose();
        }
    }
    return;
}
else
{
    try
    {
        alphaBitmap = BitmapGenerator.GenerateAlphaBitmap();

        // Create a surface from our alpha bitmap
        if(surface == null)
            surface = new Surface(device, alphaBitmap, Pool.SystemMemory);

        // Get the unmanaged pointer
        unmanagedSurface = surface.GetObjectByValue(DxMagicNumber);

        if (vmr9mixerBitmap == null)
            vmr9mixerBitmap = (IVMRMixerBitmap9)vmr9;


        // Set Alpha Bitmap Parameters for using a Direct3D surface
        alphaBmp = new VMR9AlphaBitmap();
        alphaBmp.dwFlags = VMR9AlphaBitmapFlags.EntireDDS;
        alphaBmp.pDDS = unmanagedSurface;
        alphaBmp.rDest = GetDestRectangle();
        alphaBmp.fAlpha = 1.0f;

        // Set Alpha Bitmap Parameters
        hr = vmr9mixerBitmap.SetAlphaBitmap(ref alphaBmp);
        DsError.ThrowExceptionForHR(hr);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
}

这是等待更新事件的线程。

    Thread overlayupdatethreadhandle = new Thread(new ThreadStart(overlayupdatethread));
            overlayupdatethreadhandle.Start();

    private void overlayupdatethread()
    {
        do
        {
            overlayupdateeventhandle.WaitOne();
            ShowHideBitmap(GlobalVar.m_ShowOverlay);
        } while (true);
    }

我尝试使用在间隔为100毫秒的背景下运行的计时器更新此叠加层。使用计时器工作正常,但对于此操作,使用计时器是不好的选择。所以我采用了线程概念。

为什么从线程调用时接口失败并且在从菜单选项调用时工作正常?我应该照顾任何特别的东西吗?我甚至尝试过参数化线程,但没有运气。

提前感谢您的帮助。

编辑:如果从主线程调用ShowHideBitmap,那么每件事都可以。如果从工作线程调用ShowHideBitmap,COM对象将创建Exception。如何处理这种跨线程操作?

2 个答案:

答案 0 :(得分:4)

异常是乱的,在COM中并不罕见。它的真正含义是“我不知道如何为您提供一个可以在工作线程中使用的接口引用”。这是一种常见的事故,这些COM组件根本就不是线程安全的。并且他们通过处理它来强制执行,将工作线程中的调用自动编组到所有者线程。或者根本不让你从另一个线程中使用它们,因为编组将毫无意义,使其变得太慢。 VMR属于后一类。

这与.NET非常不同,它还有一个很多类完全不符合线程的类。基本的东西,例如,没有集合类。但是它允许你在一个线程中使用这些类,让你自己使它成为线程安全的。这当然经常出错,使用正确的锁定是一种技巧。

COM一直是设计中的线程感知。由于线程很难做到正确的理念所以应该由聪明的人来照顾。其中95%的时间都是如此。并在剩下的时间给你一个主要的偏头痛。当COM负责穿线时,由难以诊断的差导致诱发的偏头痛类型。如果没有,那就是糟糕的错误报告。

嗯,没法,你真的必须从创建VMR实例的同一个线程中使用该接口。没办法。

答案 1 :(得分:1)

在尝试使用Delphi库中的Listener / Event处理程序对象时,我遇到了错误E_NOINTERFACE。解决编组和编组的问题不同的线程我保存了分配监听器的线程调度程序,然后使用它来触发事件。

接口:

[ComVisible(true)]
[Guid("2FFC2C20-A27B-4D67-AEA3-350223D3655F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDataSystemInterfaceEventListener
{
    void OnIntializeCompleted(int status);
    void OnTerminateCompleted(int status);
    void OnRunCompleted(int status);
}

[ComVisible(true)]
[Guid("B9953413-A8C9-4CE2-9263-B488CA02E7EC")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDataSystemInterface
{
    void Intialize(string config);
    void StartRun(string conditions);
    void StopRun();
    void Terminate();        

    IDataSystemInterfaceEventListener Listener { get; set; }
}

然后实现(通知Dispatcher.CurrentDispatcher存储)

[ComVisible(true)]
[Guid("0818F830-DA37-4167-BF31-3A2C55A9BF2B")]        
public class DataSystemModule : IDataSystemInterface
{
    private Dispatcher m_dispatcherListener = null;
    private IDataSystemInterfaceEventListener m_listener = null;
    public IDataSystemInterfaceEventListener Listener
    {
        get
        {
            return m_listener;
        }
        set
        {
            m_dispatcherListener = Dispatcher.CurrentDispatcher;
            m_listener = value;
        }
    } 
}

然后在代码中:

if (Listener != null)
{
    m_dispatcherListener.Invoke((Action)delegate()
    {
        Listener.OnTerminateCompleted((int)TerminateStatus.Completed);
    });
}

如果在不同的线程中调用Listener,它将产生错误