我认为我的问题类似于Getting CLSID for a DLL file?。
我有一个带有一些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
}
}
}
答案 0 :(得分:8)
你无法从COM DLL中获取它,但是你可以从类型库中获取它。我很确定MIDL编译器有一个转换来反编译一个类型库,但解析IDL并不像使用TypeLib API那么容易。
更复杂的是,类型库通常作为资源存储在DLL中。因此,您需要提取资源,然后使用TypeLib API打开它。
从LoadTypeLibEx
开始,它会返回一个ITypeLib*
接口指针(你知道你需要COM来获取有关COM库的信息,对吧?)。这实际上将为您执行资源提取步骤。
然后,请致电ITypeLib::GetTypeInfoCount
以了解有多少种类型。为每个调用ITypeLib::GetTypeInfoType
来查找接口和coclasses。然后拨打ITypeLib::GetTypeInfo
,然后拨打ITypeInfo::GetDocumentation
以获取名称。
到目前为止看起来你已经拥有了这一切。接下来,您需要使用ITypeInfo::GetTypeAttr
(不是ITypeLib::GetLibAttr
)获得的类型的GUID。这会为您提供TYPEATTR
结构,其中包含guid
字段。
从相同的TYPEATTR
结构中,您需要cImplTypes
字段。与ITypeInfo::GetRefTypeOfImplType
一起使用可以将每个coclass与它实现的接口进行匹配。
请注意,接口和实现coclass之间不能保证1:1的关系。并且界面可以与coclass在不同的库中。
答案 1 :(得分:5)
对Ben Voigt的回答几乎没有提及:并非每个COM DLL都有一个类型库。在你的情况下,似乎,它确实;但这不是一个要求。唯一坚如磐石的要求是DLL导出函数DllGetClassObject(),您可以在其中传递CLSID并返回对象工厂。
您可以加载库并为系统上的每个已注册的CLSID调用DllGetClassObject(在HKCR \ CLSID下扫描注册表以获取其列表)。获得有效对象的是DLL支持的对象。现在,理论上,甚至不要求DLL支持的CLSID被注册;我可以设想一个实现私有对象类的DLL,只有目标客户端才知道,而其他人不应该这样做。但这是一个非常非常奇特的场景;首先,通过CLSID查找DLL路径的常规COM机制将会破坏这些机制。客户端必须直接加载DLL。
您还可以扫描注册表以查找正在考虑的DLL注册为InprocServer32的CLSID;在私人课程的情况下,这将再次打破。您可以在regedit
中进行注册表搜索,搜索数据。此外,您还必须处理文件名案例问题,短名称和长名称,硬链接,环境变量替换等。所以我不推荐它。
答案 2 :(得分:0)
您可能希望查看WiX的热量实用程序中的源代码,它可以执行相同的操作: