Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Given a COM DLL, extract all classes CLSID and corresponding interface name

Tags:

c++

windows

com

My question is similar to Getting CLSID for a DLL file?, I think.

I have a directory with some DLLs, each one implementing one or more COM interfaces. I would like to get:

1) Each interface name 2) The CLSID of the class implementing the interface

For each DLL. It's important that everything can be done programatically (So I can't use some sort of COM browser and manually look up for that information).

Later I will lookup the CLSID given the interface name and call some methods using IDispatch.

One alternative seems to be scanning the registry trying to match the type, interface and class GUID and the .dll filename. But that seems to be slow and not robust.

Does someone has a clear solution to this problem?

EDIT:

With the response of Ben Voigt, I came with the following code which suit my needs:

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
        }
    }
}
like image 543
douglaz Avatar asked Jan 10 '11 21:01

douglaz


1 Answers

You can't get that from the COM DLL, but you can get it from the typelib. I'm pretty sure the MIDL compiler has a switch to decompile a typelib, but parsing IDL wouldn't be as easy as using the TypeLib API.

To complicate matters, the typelib is often stored as a resource inside the DLL. So you'd extract the resource, and open it with the TypeLib API.

Start with LoadTypeLibEx which will return you an ITypeLib* interface pointer (you knew you were going to need COM in order to get information about COM libraries, right?). This will actually do the resource extraction step for you.

Then, call ITypeLib::GetTypeInfoCount to find out how many types there are. Call ITypeLib::GetTypeInfoType for each one to find the interfaces and coclasses. And call ITypeLib::GetTypeInfo followed by ITypeInfo::GetDocumentation to get the name.

It looks like you have all of this so far. Next you need the GUID of the type, which is gotten with ITypeInfo::GetTypeAttr (not ITypeLib::GetLibAttr). That gives you a TYPEATTR structure, which has a guid field.

From the same TYPEATTR structure, you'll need the cImplTypes field. That together with ITypeInfo::GetRefTypeOfImplType will let you match up each coclass to the interfaces it implements.

Note that there's not guaranteed to be a 1:1 relationship between interfaces and implementation coclasses. And the interface can be in a different library from the coclass.

like image 167
Ben Voigt Avatar answered Oct 05 '22 21:10

Ben Voigt