Учитывая COM DLL, извлеките все классы CLSID и соответствующее имя интерфейса - PullRequest
7 голосов
/ 11 января 2011

Мой вопрос похож на Получение CLSID для DLL-файла? , я думаю.

У меня есть каталог с некоторыми DLL, каждая из которых реализует один или несколько COM-интерфейсов. Я хотел бы получить:

1) Каждое имя интерфейса 2) CLSID класса, реализующего интерфейс

Для каждой DLL. Важно, чтобы все могло быть сделано программно (поэтому я не могу использовать какой-либо браузер COM и вручную искать эту информацию).

Позже я буду искать CLSID по имени интерфейса и вызывать некоторые методы, используя IDispatch.

Одна из альтернатив, похоже, сканирует реестр, пытаясь сопоставить тип, интерфейс и класс GUID и имя файла .dll. Но это кажется медленным и не надежным.

Есть ли у кого-нибудь ясное решение этой проблемы?

EDIT:

С ответом Бена Фойгта я пришел со следующим кодом, который соответствует моим потребностям:

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 ]

8 голосов
/ 11 января 2011

Вы не можете получить это из COM DLL, но вы можете получить это из библиотеки типов. Я почти уверен, что в компиляторе MIDL есть ключ для декомпиляции библиотеки типов, но разбор IDL не будет таким простым, как использование API TypeLib.

Чтобы усложнить ситуацию, библиотека типов часто хранится в виде ресурса внутри DLL. Поэтому вы должны извлечь ресурс и открыть его с помощью API TypeLib.

Начните с LoadTypeLibEx, который вернет вам указатель интерфейса ITypeLib* (вы знали, что вам понадобится COM для получения информации о библиотеках COM, верно?). Это фактически сделает шаг извлечения ресурсов для вас.

Затем позвоните ITypeLib::GetTypeInfoCount, чтобы узнать, сколько существует типов. Вызовите ITypeLib::GetTypeInfoType для каждого, чтобы найти интерфейсы и коклассы. И позвоните ITypeLib::GetTypeInfo, а затем ITypeInfo::GetDocumentation, чтобы получить имя.

Похоже, у вас все это есть до сих пор. Далее вам нужен GUID типа, который получается с ITypeInfo::GetTypeAttr (не ITypeLib::GetLibAttr). Это дает вам структуру TYPEATTR, которая имеет поле guid.

Из той же структуры TYPEATTR вам потребуется поле cImplTypes. Это вместе с ITypeInfo::GetRefTypeOfImplType позволит вам сопоставить каждый coclass с интерфейсами, которые он реализует.

Обратите внимание, что не гарантируется связь 1: 1 между интерфейсами и классами реализации. И интерфейс может быть в другой библиотеке от Coclass.

5 голосов
/ 11 января 2011

Несколько замечаний к ответу Бена Фойгта: не у каждой библиотеки DLL DLL есть библиотека типов. В вашем случае, кажется, это так; но это не требование. Единственное твердое требование состоит в том, что DLL экспортирует функцию DllGetClassObject (), где вы передаете CLSID и возвращаете фабрику объектов.

Вы можете загрузить библиотеку и вызывать DllGetClassObject для каждого зарегистрированного CLSID в системе (просмотрите реестр в HKCR \ CLSID, чтобы увидеть их список). Те, где вы возвращаете верный объект, это те, которые поддерживает DLL. Теперь, теоретически, даже не требуется, чтобы CLSID, которые поддерживает DLL, были зарегистрированы; Я могу представить библиотеку DLL, которая реализует классы закрытых объектов, о которых знает только предполагаемый клиент, и никто другой не должен. Но это очень, очень экзотический сценарий; во-первых, обычный механизм COM поиска пути к DLL по CLSID не сработает. Клиент должен был бы загрузить DLL напрямую.

Вы также можете сканировать реестр на наличие идентификатора CLSID, в котором рассматриваемая DLL зарегистрирована как InprocServer32; это снова сломается в случае частных занятий. Вы можете сделать поиск по реестру в regedit, поиск по данным. Кроме того, вам придется иметь дело с проблемами с именами файлов, короткими и длинными именами, жесткими ссылками, подстановкой переменных среды и так далее. Поэтому я бы не рекомендовал это.

РЕДАКТИРОВАТЬ: просто подумал о другом пути. Загрузите Regmon, запустите его и вызовите regsvr32 для DLL. Затем посмотрите, к чему тронут CLSID.

0 голосов
/ 11 января 2011

Возможно, вы захотите взглянуть на исходный код утилиты WiX, которая делает то же самое:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...