C++ 获取COM对象的DLL文件,而不使用c+中的CLSID和注册表+;

C++ 获取COM对象的DLL文件,而不使用c+中的CLSID和注册表+;,c++,dll,com,directshow,C++,Dll,Com,Directshow,是否可以在不使用CLSID和注册表查找的情况下获取已加载COM对象的DLL文件名 我有一个IUnknown或者在我的例子中有一个IBaseFilter接口指针,现在我想获取创建此COM对象的DLL文件名。我可以使用对象点地址反向查找创建模块的加载模块吗?然后让HMODULE在GetModuleFileName中使用它,当然只需要使用一些技巧。对象本身在堆上,堆是共享的,但是您可以看到它的虚拟表所在的位置——它应该几乎普遍位于创建者二进制文件的只读数据部分 因此,加载对象中的第一个指针,因为Win

是否可以在不使用CLSID和注册表查找的情况下获取已加载COM对象的DLL文件名


我有一个
IUnknown
或者在我的例子中有一个
IBaseFilter
接口指针,现在我想获取创建此COM对象的DLL文件名。我可以使用对象点地址反向查找创建模块的加载模块吗?然后让
HMODULE
GetModuleFileName
中使用它,当然只需要使用一些技巧。对象本身在堆上,堆是共享的,但是您可以看到它的虚拟表所在的位置——它应该几乎普遍位于创建者二进制文件的只读数据部分

因此,加载对象中的第一个指针,因为Windows COM ABI中的虚拟表指针就位于该位置:

IBaseFilter* pFilter = ...;
char* vtbl = *reinterpret_cast<char**>(pFilter);
IBaseFilter*pFilter=。。。;
char*vtbl=*重新解释(pFilter);
然后,我最初建议对
EnumProcessModules()
进行一些循环,例如,对每个模块调用
GetModuleInformation()
,检查
vtbl
指针是否在其内存范围内。愚蠢的我,我忘记了VirtualQueryEx(),所以最好按照Roman在回答中描述的那样做

当然,所有这些只适用于进程内COM对象,并且不涉及代理。不过,我认为它在DirectShow中仍然有用


另请参见有关使用IPersist::GetClassId()和注册表查找的注释,它应该很好地应用于大多数DirectShow筛选器。

Yirkha的答案很有说服力,我要补充两个注意事项:

<> > DirectShow过滤器通常是旧式的C++ COM对象,其中虚拟方法表驻留在代码段中,只要我们在单进程中,就没有代理/存根代码。也就是说,从接口指针解析模块的方法很有效

  • EnumProcessModules
    /
    GetModuleInformation
    walk-rough模块列表更容易替换
    VirtualQueryEx
    可以直接定位DLL的基址:


  • 另外,这是我们在这两方面都做过的事情,在这两方面都做过。

    没有一个文档化的方法来发现这一点是COM的核心。您可能会发现一个存根,当然不是您希望找到的。这只适用于进程内COM对象。进程外COM对象在另一个进程中运行,本地进程使用代理与另一个进程通信。因此COM对象的vtable将指向本地进程中与本地进程的模块列表中的任何DLL都不匹配的内存,或者至少肯定不是实际COM对象的原始模块。这是正确的,很好的一点-它将只显示编组对象的创建者,或者可能根本不显示,在这种情况下,虚拟表可能是在堆上动态创建的。这似乎适用于DirectShow COM筛选器,我不知道其他代理/存根场景。谢谢。DShow过滤器都在处理中,所以技巧看起来不错。当然,过滤器都实现了
    IPersist
    ,所以注册表查找选项仍然作为一种替代路径存在。我已经使用了注册表查找,但是由于我们也在没有注册的情况下加载了过滤器,所以需要这个技巧。
    const VOID* pvVirtualTable = *((const VOID**) pBaseFilter);
    MEMORY_BASIC_INFORMATION Information;
    if(VirtualQueryEx(GetCurrentProcess(), pvVirtualTable, &Information,
      sizeof Information))
    {
      TCHAR pszPath[MAX_PATH] = { 0 };
      if(GetModuleFileName((HMODULE) Information.AllocationBase, pszPath,
        _countof(pszPath)))
      {