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

时间:2011-01-10 21:47:00

标签: c++ windows com

我认为我的问题类似于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
        }
    }
}

3 个答案:

答案 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中进行注册表搜索,搜索数据。此外,您还必须处理文件名案例问题,短名称和长名称,硬链接,环境变量替换等。所以我不推荐它。

编辑:想到另一种方式。下载Regmon,运行它,并在DLL上调用regsvr32。然后看看CLSID被触摸了什么。

答案 2 :(得分:0)

您可能希望查看WiX的热量实用程序中的源代码,它可以执行相同的操作:

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