Аннотация:
Для получения информации о COM-объектах существуют специальные утилиты (смотри хотя бы входящий в состав Студии «OLE/COM Object Viewer»), которые и расскажут, и покажут, и IDL напишут. Но иногда необходимо получать эти данные «на лету», во время выполнения программы. Механизмам получения информации об интерфейсах и посвящена эта статья.
Здравствуйте, Павел Коломиец, Вы писали:
ПК>Статья: ПК>Получение информации о COM-интерфейсах
ПК>Авторы: ПК> Павел Коломиец
ПК>Аннотация: ПК>Для получения информации о COM-объектах существуют специальные утилиты (смотри хотя бы входящий в состав Студии «OLE/COM Object Viewer»), которые и расскажут, и покажут, и IDL напишут. Но иногда необходимо получать эти данные «на лету», во время выполнения программы. Механизмам получения информации об интерфейсах и посвящена эта статья.
D>А что, читать ее нельзя?
На сегодня вводится не только привязка уже опубликованных статей к форумам, но и привязка анонсов будущих статей. Это сделано, что бы читатели форума могли зараннее узнать о статьях, которые будут опубликованны в следующем номере RSDN Mag.
ЗЫ: Правда насчёт именно этой статьи я ручаться не могу.
Все это действительно здорово. И крайне своевременно!
Но остались непроясненные моменты: Как можно выяснить, что интерфейс унаследован от какого-то другого и а) определить от какого б) отделить свои методы от унаследованных?
Это точно возможно, поскольку #import в VC это делает и тоже основывается на библиотеке типов.
РМ>Как можно выяснить, что интерфейс унаследован от какого-то другого и а) определить от какого б) отделить свои методы от унаследованных?
Это определяет значение cImplTypes структуры TYPEATTR для интерфейса, но там скорее всего всегда 1, кроме IUnknown.
a) "От какого" определяется так: через GetRefTypeOfImplType(0,&h) и последующим GetRefTypeInfo(h,&p).
б) Состав методов в TypeInfo определен ТОЛЬКО для этого интерфейса, т.е. ничего делать специально не нужно.
РМ>>Как можно выяснить, что интерфейс унаследован от какого-то другого и а) определить от какого б) отделить свои методы от унаследованных?
Vi2>Это определяет значение cImplTypes структуры TYPEATTR для интерфейса, но там скорее всего всегда 1, кроме IUnknown. Vi2>a) "От какого" определяется так: через GetRefTypeOfImplType(0,&h) и последующим GetRefTypeInfo(h,&p).
Thanx, будем смотреть.
Vi2>б) Состав методов в TypeInfo определен ТОЛЬКО для этого интерфейса, т.е. ничего делать специально не нужно.
Вроде бы надо. Если загрузить в пример к статье msxml.dll, то отлично видно, что, например, IXMLDOMElement содержит и IUnknown, и методы IXMLDOMNode, и еще может быть чего-то, хотя, кажется, IDispatch почему-то нет. Или я чего-то не понимаю?
Vi2>>б) Состав методов в TypeInfo определен ТОЛЬКО для этого интерфейса, т.е. ничего делать специально не нужно.
РМ>Вроде бы надо. Если загрузить в пример к статье msxml.dll, то отлично видно, что, например, IXMLDOMElement содержит и IUnknown, и методы IXMLDOMNode, и еще может быть чего-то, хотя, кажется, IDispatch почему-то нет. Или я чего-то не понимаю?
Да, я ввел в заблуждение. Придется выводить...
Если интерфейс custom (т.е. в итоге не порождается от IDispatch, а чисто от IUnknown), то по его IID возвращается реальное описание интерфейса. Соответственно, GetRefTypeOfImplType(0,&h) и GetRefTypeInfo(h,&p) вернут его ближайшую порождающую базу. Количество функций в интерфейсе точно равно количеству заявленных именно этим интерфейсом. Например, для интерфейса
interface Ix : IUnknown interface Ix2 : Ix
{ {
[...] HRESULT XXXX(...); [...] HRESULT YYYY(...);
} }
TYPEATTR::cbSizeInstance == 4 4
TYPEATTR::typekind == TKIND_INTERFACE TKIND_INTERFACE
TYPEATTR::cFuncs == 1 // описание метода XXXX 1 // описание метода YYYY
TYPEATTR::cVars == 0
TYPEATTR::cImplTypes == 1 // описание базы IUnknown 1 // описание базы Ix
TYPEATTR::cbSizeVft == 16 // 3 метода базы + 1 свой 20 // 4 метода базы + 1 свой
Если интерфейс dual (т.е. в итоге порождается от IDispatch), то возвращается описание dispinterface, который совпадает по описанию с исходным интерфейсом. Это не описание IDispatch интерфейса и не описание исходного. Это специфическое описание специфического интерфейса — дисп-интерфейса. Поскольку дисп-интерфейсы не наследуются, то они всегда полностью содержат в себе описания всех методов. Их GetRefTypeOfImplType(0,&h) и GetRefTypeInfo(h,&p) вернут его ближайшую порождающую базу — а это всегда IDispatch. Дополнительно, их GetRefTypeOfImplType(-1,&h) и GetRefTypeInfo(h,&p) вернут человеческое описание исходного дуального (custom-ного) интерфейса.
interface Ix : IDispatch interface Ix2 : Ix
{ {
[...] HRESULT XXXX(...); [...] HRESULT YYYY(...);
} }
TYPEATTR::cbSizeInstance == 4 4
TYPEATTR::typekind == TKIND_DISPATCH TKIND_DISPATCH
TYPEATTR::cFuncs == 8 // описание всех методов + XXXX 9 // описание всех методов + YYYY
TYPEATTR::cVars == 0
TYPEATTR::cImplTypes == 1 // описание базы IDispatch 1 // описание базы IDispatch
TYPEATTR::cbSizeVft == 28 // 7 методов базы + 1 свой 32 // 8 методов базы + 1 свой
Здравствуйте, Рома Мик, Вы писали:
РМ>Все это действительно здорово. И крайне своевременно!
Спасибо
РМ>Но остались непроясненные моменты: [...] б) отделить свои методы от унаследованных?
Отделять не надо. Информацию о функциях родителя интерфеса через GetFuncDesc получить нельзя. Конечно, пример показывает реализацию методов IUnknown и IDispatch, но неболее того. Обрати внимание на то что методы этих интерфесов помечены как restricted. То есть в поле FUNCDESC.wFuncFlags установлен флаг FUNCFLAG_FRESTRICTED, который обозначает, что
The function should not be accessible from macro languages. This flag is intended for system-level functions or functions that type browsers should not display.
Здравствуйте, Павел Коломиец, Вы писали:
ПК>Статья:
ПК>Авторы: ПК> Павел Коломиец
ПК>Аннотация: ПК>Для получения информации о COM-объектах существуют специальные утилиты (смотри хотя бы входящий в состав Студии «OLE/COM Object Viewer»), которые и расскажут, и покажут, и IDL напишут. Но иногда необходимо получать эти данные «на лету», во время выполнения программы. Механизмам получения информации об интерфейсах и посвящена эта статья.
Я бы не стал приуменьшать значение статьи Known Unknown. Разработчик компонента не обязан вносить все интерфейсы в библиотеку типов. Вот в этих то случаях и приходится применять всякие трюки... Правда весьма сочувствую тому, кому такое проворачивать надо