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

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

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

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

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

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

一个替代似乎是扫描registry试图匹配types,接口和类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 } } } 

你不能从COM DLL中获取,但你可以从typelib中获取它。 我很确定MIDL编译器有一个反编译typelib的开关,但是解析IDL不会像使用TypeLib API那么简单。

使事情复杂化,typelib通常被存储在DLL中的一个资源。 所以你要提取资源,并用TypeLib API打开它。

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

然后,调用ITypeLib::GetTypeInfoCount来找出有多少类型。 调用ITypeLib::GetTypeInfoType为每个找到接口和coclasses。 然后调用ITypeLib::GetTypeInfo然后调用ITypeInfo::GetDocumentation来获取名称。

看起来你到目前为止都是这样。 接下来,您需要使用ITypeInfo::GetTypeAttr (而不是ITypeLib::GetLibAttrITypeInfo::GetTypeAttr的类型的GUID。 这给你一个TYPEATTR结构,它有一个guid字段。

从相同的TYPEATTR结构中,您将需要cImplTypes字段。 与ITypeInfo::GetRefTypeOfImplType一起使您可以将每个coclass与它实现的接口进行匹配。

请注意,接口和实现类之间不能保证1:1的关系。 接口可以在与coclass不同的库中。

几乎没有告诫Ben Voigt的回答:不是每个COM DLL都有一个typelib。 就你而言,似乎是这样; 但这不是要求。 唯一坚如磐石的要求是DLL导出函数DllGetClassObject(),在那里你传递一个CLSID并取回一个对象工厂。

您可以加载该库并为系统上的每个注册的CLSID调用DllGetClassObject(扫描HKCR \ CLSID下的注册表以获取这些列表)。 你得到一个有效的对象是那些DLL支持的。 现在,从理论上讲,DLL支持的CLSID甚至不需要注册。 我可以设想一个DLL,实现私人对象类,只有预期的客户端知道,没有人应该。 但这是一个非常非常奇特的场景。 一方面,通过CLSID查找DLL路径的常规COM机制将会破坏这些机制。 客户端将不得不直接加载DLL。

您也可以扫描注册表中的CLSID,其中考虑的DLL被注册为Inprocserver32; 在私人课程的情况下,这又将会打破。 您可以在注册表中进行注册表搜索,搜索数据。 此外,你必须处理文件名的情况下,短名称,长名称,硬链接,环境变量替代等。 所以我不会推荐它。

编辑:只是想到另一种方式。 下载Regmon,运行它,并调用DLL上的regsvr32。 然后观看CLSID的触摸。

你可能想看看WiX的热工具中的源代码,它也是这样做的:

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