给定一个COM DLL,提取所有类的CLSID和相应的接口名称

问题描述 投票:0回答:3

我的问题类似于获取 DLL 文件的 CLSID?,我想。

我有一个包含一些 DLL 的目录,每个 DLL 都实现一个或多个 COM 接口。我想要得到:

1) 各接口名称 2)实现接口的类的CLSID

对于每个 DLL。重要的是一切都可以通过编程完成(所以我不能使用某种 COM 浏览器并手动查找该信息)。

稍后我将查找给定接口名称的 CLSID 并使用 IDispatch 调用一些方法。

一种替代方法似乎是扫描注册表,尝试匹配类型、接口和类 GUID 以及 .dll 文件名。但这似乎很慢而且不稳健。

有人对这个问题有明确的解决方案吗?

编辑:

根据 Ben Voigt 的回复,我提供了以下适合我的需求的代码:

ITypeLib *typelib;
ITypeInfo *typeinfo;
LoadTypeLibEx(_T("c:\\mydir\\mycom1"), REGKIND_NONE, &typelib);
for (UINT i = 0;i < typelib->GetTypeInfoCount();++i) {
    TYPEKIND typekind;
    typelib->GetTypeInfoType(i, &typekind);
    if (typekind == TKIND_COCLASS) {
        // class!
        CComBSTR className;
        TYPEATTR *typeattr;
        typelib->GetTypeInfo(i, &typeinfo);
        typeinfo->GetDocumentation(MEMBERID_NIL, &className, NULL, NULL, NULL);
        typeinfo->GetTypeAttr(&typeattr);
        GUID classGUID = typeattr->guid;
        for (UINT j = 0;j < typeattr->cImplTypes;++j) {
            // interface!
            CComBSTR interfaceName;
            HREFTYPE hreftype;
            ITypeInfo *classtypeinfo;
            typeinfo->GetRefTypeOfImplType(j, &hreftype);
            typeinfo->GetRefTypeInfo(hreftype, &classtypeinfo);
            classtypeinfo->GetDocumentation(MEMBERID_NIL, &interfaceName, NULL, NULL, NULL);
            // associate interfaceName with classGUID here
        }
    }
}
c++ windows com
3个回答
9
投票

您无法从 COM DLL 中获取它,但可以从类型库中获取它。我很确定 MIDL 编译器有一个反编译 typelib 的开关,但解析 IDL 并不像使用 TypeLib API 那么容易。

让事情变得复杂的是,类型库通常作为资源存储在 DLL 中。因此,您需要提取资源,并使用 TypeLib API 打开它。

LoadTypeLibEx
开始,它将返回一个
ITypeLib*
接口指针(您知道您将需要 COM 来获取有关 COM 库的信息,对吗?)。这实际上会为您完成资源提取步骤。

然后,拨打

ITypeLib::GetTypeInfoCount
来了解有多少种类型。为每一个调用
ITypeLib::GetTypeInfoType
来查找接口和组件类。然后拨打
ITypeLib::GetTypeInfo
然后拨打
ITypeInfo::GetDocumentation
即可获取姓名。

到目前为止,您似乎已经拥有了所有这些。接下来,您需要该类型的 GUID,该 GUID 通过

ITypeInfo::GetTypeAttr
(而不是
ITypeLib::GetLibAttr
)获得。这给你一个
TYPEATTR
结构,它有一个
guid
字段。

在相同的

TYPEATTR
结构中,您需要
cImplTypes
字段。与
ITypeInfo::GetRefTypeOfImplType
一起,您可以将每个组件类与其实现的接口相匹配。

请注意,不保证接口和实现组件类之间存在 1:1 的关系。并且接口可以位于与组件类不同的库中。


6
投票

Ben Voigt 的回答有几点需要注意:并非每个 COM DLL 都有类型库。就你的情况而言,似乎确实如此;但这不是一个要求。唯一可靠的要求是 DLL 导出函数 DllGetClassObject(),您可以在其中传递 CLSID 并取回对象工厂。

您可以加载该库并为系统上每个已注册的 CLSID 调用 DllGetClassObject(扫描 HKCR\CLSID 下的注册表以获取这些列表)。您返回的有效对象是 DLL 支持的对象。现在,从理论上讲,甚至不需要注册 DLL 支持的 CLSID;我可以设想一个 DLL 实现私有对象类,只有目标客户知道,其他人不知道。但这是一个非常非常奇特的场景;一方面,通过 CLSID 查找 DLL 路径的常规 COM 机制将被破坏。客户端必须直接加载 DLL(编辑:或在可执行文件的清单中引用 DLL,如免注册 COM 所允许的那样)。

您还可以扫描注册表中的 CLSID,其中所考虑的 DLL 注册为 InprocServer32;如果是私人课程,这又会被打破。您可以在

regedit
中进行注册表搜索,在数据中搜索。此外,您还必须处理文件名大小写问题、短名称与长名称、硬链接、环境变量替换等。所以我不会推荐它。

编辑:只是想到了另一种方法。下载 Regmon,运行它,然后在 DLL 上调用 regsvr32。然后观察哪些 CLSID 被触及。


0
投票

您可能想查看 WiX 的 heat 实用程序中的源代码,它做同样的事情:

http://wix.sourceforge.net/manual-wix3/heat.htm

© www.soinside.com 2019 - 2024. All rights reserved.