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

dou*_*laz 7 c++ windows com

我的问题类似于获取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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*igt 8

你不能从COM DLL中获得它,但你可以从类型库中获取它.我很确定MIDL编译器有一个转换来反编译一个类型库,但解析IDL并不像使用TypeLib API那么容易.

更复杂的是,类型库经常作为资源存储在DLL中.因此,您将提取资源,并使用TypeLib API打开它.

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

然后,打电话ITypeLib::GetTypeInfoCount找出有多少种类型.调用ITypeLib::GetTypeInfoType为每一个找到的接口和组件类.并呼吁ITypeLib::GetTypeInfo之后ITypeInfo::GetDocumentation得到的名称.

到目前为止看起来你已经完成了这一切.接下来,您需要使用类型的GUID ITypeInfo::GetTypeAttr(不是ITypeLib::GetLibAttr).这会给你一个TYPEATTR结构,它有一个guid字段.

从相同的TYPEATTR结构,你将需要该cImplTypes领域.与它一起ITypeInfo::GetRefTypeOfImplType将允许您将每个coclass与它实现的接口相匹配.

请注意,接口和实现coclass之间不能保证1:1的关系.并且界面可以与coclass位于不同的库中.


Sev*_*yev 5

Ben Voigt的答案很少警告:并非每个COM DLL都有一个类型库。在您看来,确实如此;但这不是必需的。唯一坚如磐石的要求是DLL导出函数DllGetClassObject(),在其中传递CLSID并返回对象工厂。

您可以加载该库并为系统上每个已注册的CLSID调用DllGetClassObject(扫描HKCR \ CLSID下的注册表以获取这些列表)。那些返回有效对象的对象是DLL支持的对象。现在,从理论上讲,甚至不需要注册DLL支持的CLSID。我可以设想一个DLL,该DLL实现只有目标客户端知道的私有对象类,而其他人则不应该知道。但这是一个非常非常奇特的场景。一方面,通过CLSID查找DLL路径的常规COM机制将因此而中断。客户端必须直接加载DLL。

您还可以在注册表中扫描CLSID,其中所考虑的DLL已注册为InprocServer32;同样,这将在私人课程的情况下中断。您可以在regedit中搜索注册表,搜索数据。此外,您还必须处理文件名大小写问题,短名称与长名称,硬链接,环境变量替换等。所以我不推荐它。

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