Com 使用IPersistStream::Load从.GRF文件加载IFilterGraph无法实例化使用CoreRegisterClassObject注册的私有进程内筛选器

Com 使用IPersistStream::Load从.GRF文件加载IFilterGraph无法实例化使用CoreRegisterClassObject注册的私有进程内筛选器,com,directshow,Com,Directshow,从应用程序中的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 = pPersistSt

从应用程序中的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实现调用的CoreRegisterObject在EXE中本地注册。当ICLASFACTS实现接收ICLASTFACK::CealEngultCuff.< /P>时,这些过滤器是用C++新创建的。
    HRESULT hr = CoRegisterClassObject(*m_pTemplate->m_ClsID, this, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &m_RegisterKey);
当直接通过CoCreateInstance创建时,本地过滤器工作正常。当用C++新创建时,它们也可以工作得很好。
CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&instance);
加载包含这些本地筛选器的GRF文件不起作用,并返回未从IPersistStream::Load注册的HRESULT 0x80040154类

应用程序的IClassFactory::CreateInstance函数未被调用,但在IPersistStream::Load期间使用正确的CLSID调用了CoCreateInstance API,但它是从不同于IPersistStream::Load调用的线程调用的(在使用COM单元线程初始化的主应用程序线程上)。另一个区别是,当从IPersistStream::Load调用dwContext时,它是CLSCTX_INPROC_服务器| CLSCTX_INPROC_处理程序。但是,来自主线程的CoCreateInstance调用仍然使用此dwContext值。包括CLSCTX_INPROC_处理程序标志的CoreRegisterClassObject调用失败,返回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应用程序的建议调用CoInitializeX(NULL,Conit_APARTMENTTHREADED)。我尝试在调用CoRegisterClassObject时使用不同的上下文和标志值,但没有成功。GRF文件肯定包含进程本地筛选器的正确CLSID

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


IFilterGraph序列化是否支持使用CoreRegisterClassObject注册的进程本地筛选器?如果是这样,应用程序正在执行的操作是否存在问题?是否有任何步骤可以进一步诊断此问题?

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

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

在共享工作线程上创建筛选器图形管理器

然后,您会看到线程上的实例化调用,而您并不期望它们出现

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

一旦解决了线程问题,
CLSCTX
不应成为问题
CLSCTX\u INPROC\u SERVER
已经足够好了,您正在
CoRegisterClassObject
调用中选择上下文标志,因此准备COM上下文和使用.GRF加载内部组件调用类工厂就足够了


如果您是从UI线程创建图形,或者是从正常操作中包含消息循环的线程创建图形,
CLSID\u FilterGraphNoThread
应该与常规
CLSID\u FilterGraphNoThread
一样工作
CLSID_FilterGraphNoThread基本上是一种稀有品种,但Windows Media Player确实在内部使用了它,也许这就是为什么存在这种过滤器图形类变体的原因。

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

从将协同创建实例处理本地COM对象的每个单元调用CoreRegisterClassObject

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

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


上有一个关于COM公寓的有用MSDN解释,谢谢,Roman。使用CLSID_FilterGraphNoThread解决了这个问题。大概为了使它与CLSID_FilterGraph一起工作,我需要找到一种方法从filter graph线程运行我的CoreRegisterClassObject代码——也许我可以调用一个filter graph manager函数,该函数调用回我自己的一些代码并从那里调用CoreRegisterClassObject。作为一个想法,你可以添加一个假过滤器,这样filter graph manager就可以在正确的线程上调用它的一些方法。在完成图形构建和运行图形之前,您甚至可以删除其中的过滤器。在一些实验之后,看起来我只需要从每个将协同创建实例处理本地COM对象的单元调用CoRegisterClassObject。要使用CLSID_FilterGraph,还意味着从应用程序中的任何MTA线程调用CoreRegisterClassObject,并确保至少有一个MTA线程始终在运行,否则注册似乎会终止。在STA应用程序中执行此操作的最简单方法(尽管可能是浪费)是启动一个线程,该线程调用CoInitializeEx(NULL,Conit_多线程),然后CoRegisterClassObject休眠,永远不会退出。在此方面的一个小更新:每个进程只有一个MTA。在任何MTA t上注册就足够了