C# 查询接口失败,C上没有E_接口#
大家好 我是C#编程的新手。我正在开发一个基本的摄像头流媒体和静态捕捉应用程序。一旦用户静止,我将使用VMR9的位图混合概念在覆盖图上显示它 我做了什么?C# 查询接口失败,C上没有E_接口#,c#,visual-studio-2008,camera,directshow,C#,Visual Studio 2008,Camera,Directshow,大家好 我是C#编程的新手。我正在开发一个基本的摄像头流媒体和静态捕捉应用程序。一旦用户静止,我将使用VMR9的位图混合概念在覆盖图上显示它 我做了什么? 我正在使用来自的C#direct show库 首先,我得到所有必需的过滤器接口。查找连接的捕获设备。使用源过滤器和vmr9为预览管脚调用渲染流。源过滤器、样本抓取器和静态PIN的空呈现器 我有三个菜单按钮->静止,显示覆盖和隐藏覆盖 我正在使用该库中提供的位图混合器示例 每次用户按下“拍摄静止”菜单时,图像将保存在桌面上,并将重新调整到小分
- 我正在使用来自的C#direct show库
- 首先,我得到所有必需的过滤器接口。查找连接的捕获设备。使用源过滤器和vmr9为预览管脚调用渲染流。源过滤器、样本抓取器和静态PIN的空呈现器
- 我有三个菜单按钮->静止,显示覆盖和隐藏覆盖
- 我正在使用该库中提供的位图混合器示例
- 每次用户按下“拍摄静止”菜单时,图像将保存在桌面上,并将重新调整到小分辨率,并显示在视频叠加上
- Show Overlay和hide Overlay调用ShowHideBitmap(),执行从vmr9筛选器查询VMR9BitmapMixer接口的操作,填充VMR9AlphaBitmap结构,然后调用IVMRMixerBitmap9.SetAlphaBitmap函数
- 拍摄静止后,如果我通过菜单选项调用ShowHideBitmap(),拍摄的静止图像将在覆盖上完全更新
- 这是另一个选项,在保存静止图像后立即执行覆盖的自动更新。我创建了基于事件的线程,并让它等待使用EventWaitHandle创建的更新事件。在从samplegrabber BufferCB函数返回之前,我设置了这个更新事件。这反过来会继续等待线程。在线程内部,我调用ShowHideBitmap函数。在这个场景中,我收到如下错误消息
无法将“DirectShowLib.VideoMixingRenderer9”类型的COM对象大小写为接口类型“DirectShowLib.IVMRMixerBitmap9”。此操作失败,因为对IID为“{ced175e5-1935-4820-81bd-ff6ad00c9108}”的接口的COM组件的QueryInterface调用由于以下错误而失败:不支持此类接口(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);
}
我曾尝试使用计时器更新此覆盖,计时器在后台以100ms的间隔运行。使用计时器效果良好,但对于此操作,使用计时器是一个错误的选择。因此我使用线程概念
为什么从线程调用时获取接口失败,从菜单选项调用时效果良好?我是否需要处理任何特殊的事情?我甚至尝试过参数化线程,但没有成功
提前感谢你的帮助
编辑:如果从主线程调用ShowHideBitmap,一切正常。如果从工作线程调用ShowHideBitmap,COM对象会创建异常。如何处理此跨线程操作?异常很严重,在COM中并不少见。它真正的意思是“我不知道如何为您提供可以从工作线程使用的接口引用"。这是一种常见的灾难,这些COM组件根本就不是线程安全的。它们通过处理这些组件,自动将工作线程的调用封送到所有者线程来实现这一点。或者根本不让您从另一个线程使用它们,因为封送将毫无意义,这会使它变得太慢w、 VMR属于后一类 这与.NET非常不同,它也有很多类是完全线程不安全的。同样,基本的东西,没有一个集合类是这样。但它允许您在线程中使用这些类,让您自己来确保线程安全。这经常出错。当然,使用适当的锁定是一项技能 COM一直以来都是通过设计来感知线程的。其理念是线程很难得到正确的处理,所以应该由聪明的人来处理。它在95%的时间内工作得非常好。并且在其余时间会给你带来严重的偏头痛。这种偏头痛是由COM处理线程时难以诊断的性能差引起的还有糟糕的错误报告
嗯,不行,你真的必须从创建VMR实例的同一个线程使用该接口。没有办法解决这个问题。我在尝试使用Delphi库中的侦听器/事件处理程序对象时遇到了错误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已存储)
然后在代码中:
if (Listener != null)
{
m_dispatcherListener.Invoke((Action)delegate()
{
Listener.OnTerminateCompleted((int)TerminateStatus.Completed);
});
}
如果在不同的线程中调用侦听器,则会产生错误+1。问题很好。注释,因为我不完全确定…某种程度上是预期的:大多数COM对象预期从单个线程调用…如果可以从多个线程调用,文档可能会显式调用。(我还模糊地记得,在跨线程访问对象之前,您可能需要在其他线程上初始化COM)…嗨,Alexei,是的,你是对的。从主线程以外的多个线程调用COM对象会产生此错误。我甚至尝试将此vmr9mixerBitmap接口初始化为主线程,并在ShowHideBitmap函数中使用相同的接口(而不是在此函数中创建),但结果是相同的。初始化COM,您的意思是我应该在主线程中获取接口,并在线程之间使用相同的接口?是否有关于跨线程访问此COM对象的详细说明?即使违反COM规则,底层VMR接口也可以在线程之间传递。但在本机代码中,不是托管的。在C#COM interop it没有意识到这些肮脏的技巧,我想这可能是一个问题:当它试图通过封送传递接口时,它只是无法这样做,它失去了inte
if (Listener != null)
{
m_dispatcherListener.Invoke((Action)delegate()
{
Listener.OnTerminateCompleted((int)TerminateStatus.Completed);
});
}