com - 使用 IPersistStream::Load 从 .GRF 文件加载 IFilterGraph 无法实例化使用 CoRegisterClassObject 注册的私有(private)进程内过滤器

标签 com directshow

从应用程序中的 GRF 文件加载 Directshow IFilterGraph 对于在 DLL 中全局注册的普通过滤器效果很好。

    // open structured storage file...
    hr = pStorage->OpenStream(L"ActiveMovieGraph", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
if (SUCCEEDED(hr)) {
    hr = pPersistStream->Load(pStream);
    pStream->Release();
}

但是,某些过滤器是使用从 IClassFactory 实现调用的 CoRegisterObject 在 EXE 中本地注册的。当 IClassFactory 实现收到 IClassFactory::CreateInstance 调用时,使用 C++ new 创建这些过滤器。

    HRESULT hr = CoRegisterClassObject(*m_pTemplate->m_ClsID, this, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &m_RegisterKey);

直接通过 CoCreateInstance 创建时,本地过滤器可以正常工作。当直接使用 C++ new 创建时,它们也可以正常工作。

CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&instance);

加载包含这些本地过滤器的 GRF 文件不起作用,并返回 HRESULT 0x80040154 类未从 IPersistStream::Load 注册。

应用程序的 IClassFactory::CreateInstance 函数未被调用,但在 IPersistStream::Load 期间使用正确的 CLSID 调用 CoCreateInstance API,但它是从与 IPersistStream::Load 调用不同的线程调用的(在使用以下代码初始化的主应用程序线程上) COM 公寓线程)。另一个区别是,从 IPersistStream::Load 调用时 dwContext 是 CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER。但是,来自主线程的 CoCreateInstance 调用仍然可以使用此 dwContext 值。包含 CLSCTX_INPROC_HANDLER 标志的 CoRegisterClassObject 调用失败,并显示 E_INVALIDARG。

ole32.dll!CoCreateInstance(const _GUID & rclsid, IUnknown * pUnkOuter, unsigned long dwContext, const _GUID & riid, void * * ppv)  Line 96  C++
quartz.dll!_CoCreateFilter@8()  + 0x1a bytes    
quartz.dll!CFilterGraph::OnCreateFilter()  + 0x55 bytes 
quartz.dll!CFGControl::CGraphWindow::OnReceiveMessage()  + 0x2d05 bytes 
quartz.dll!WndProc()  + 0x3e bytes  
user32.dll!_InternalCallWinProc@20()  + 0x23 bytes  
user32.dll!_UserCallWinProcCheckWow@32()  + 0xb7 bytes  
user32.dll!_DispatchMessageWorker@8()  + 0xed bytes 
user32.dll!_DispatchMessageW@4()  + 0xf bytes   
quartz.dll!ObjectThread()  + 0x65 bytes 
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes    
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes   
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes    

rclsid  {CA6B3460-28B3-4A6E-A7FC-A83CF1DEEC49}  const _GUID &
pUnkOuter   0x00000000  IUnknown *
dwContext   3   unsigned long
riid    {IID_IBaseFilter}   const _GUID &

应用程序按照 MFC 应用程序的建议调用 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)。我尝试在调用 CoRegisterClassObject 时使用不同的上下文和标志值,但没有成功。 GRF 文件肯定包含进程本地过滤器的正确 CLSID。

该行为与应用程序的 Win32 和 x64 版本相同。主机操作系统是Windows 7 x64。

IFilterGraph 序列化是否支持使用 CoRegisterClassObject 注册的进程本地过滤器?如果是这样,应用程序正在执行的操作是否存在问题?我可以采取任何步骤来进一步诊断此问题吗?

最佳答案

我想说整个 .GRF 文件故事不适合生产使用。它只是调试、开发、故障排除的有用选项。由于最初的预期用途有限,您在这里遇到了文档中没有详细概述的限制之一。

过滤器图期望过滤器由 DLL 托管(带有标记为 Both 单元模型的类),因此它会使用您的参数发出 CoCreateInstance 调用看。此外,如果您使用 CLSID_FilterGraph 过滤器图表,如 MSDN 所说,它:

Creates the Filter Graph Manager on a shared worker thread.

然后您会在您不希望的线程上看到实例化调用。

我想说你仍然可以通过合理的努力让它工作。首先,您需要尝试使用 CLSID_FilterGraphNoThread 来解决线程问题,并在调用线程上(在您已经使用 CoRegisterClassObject 准备好的单元中)进行实例化调用来电。

一旦线程问题得到解决,CLSCTX 就不会成为问题。 CLSCTX_INPROC_SERVER 已经足够好了,并且您在 CoRegisterClassObject 调用中选择上下文标志,因此准备 COM 上下文并从 .GRF 中调用您的类工厂就足够了加载内部结构。

如果您要从 UI 线程创建图表,或者从具有消息循环作为其正常操作一部分的线程创建图表,CLSID_FilterGraphNoThread 应该与常规 CLSID_FilterGraph 一样工作>。 CLSID_FilterGraphNoThread 基本上是一种稀有鸟类,但 Windows Media Player 确实在内部使用它,也许这就是过滤器图形类的这种变体存在的原因。

关于com - 使用 IPersistStream::Load 从 .GRF 文件加载 IFilterGraph 无法实例化使用 CoRegisterClassObject 注册的私有(private)进程内过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14925119/

相关文章:

c++ - 使用 CoCreateInstance 时内存泄漏

c# - COM 服务器发送空字符串,该字符串被转换为 NULL 指针

c++ - 3 使用 videoInput 或其他任何方式捕获相机

c# - 如何将 DirectShow 过滤器转换为 C++\C#?

c# - 无法在 IGraphBuilder.RenderFile 中使用 COM 异常播放 MP3 文件

c++ - UVC 相机 "Still Pin"在 Linux C++ 中捕获

c++ - 在 Visual Studio 2008 中使用 C++ 创建简单 COM 组件的示例

C++ IPC 替代本地 COM 接口(interface)?

JAVA - GPS 接收器在控制台中发送奇怪/编码的帧

windows - 如何为我的 DirectShow 过滤器制作安装程序?