2

从应用程序中的 GRF 文件加载 Directshow IFilterGraphs 对于在 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 注册的进程本地过滤器?如果是这样,应用程序正在做什么有问题吗?我可以采取任何步骤来进一步诊断此问题吗?

4

2 回答 2

2

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

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

在共享工作线程上创建 Filter Graph Manager。

然后你会在一个你不期望它们的线程上看到实例化调用。

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

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

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

于 2013-02-17T19:46:17.760 回答
1

为了未来读者的利益,这解决了这个问题:

从将 CoCreateInstance 处理本地 COM 对象的每个单元调用 CoRegisterClassObject。

要使用 CLSID_FilterGraph 加载 GRF 文件并实例化本地注册的过滤器,这也意味着从应用程序中的任何一个 MTA 线程调用 CoRegisterClassObject 并确保至少有一个 MTA 线程始终在运行,否则注册似乎会终止。

在 STA 应用程序中执行此操作的最简单方法(尽管可能很浪费)是启动一个线程,该线程调用 CoInitializeEx(NULL, COINIT_MULTITHREADED) 然后 CoRegisterClassObject 然后休眠并且永不退出。

在理解和使用 COM 线程模型中有一个有用的关于 COM 单元的 MSDN 解释

于 2013-03-08T11:38:51.107 回答