Клиент всегда взаимодействует с компонентом через
интерфейс. Для запроса у компонента интерфейса используется интерфейс IUknown. Определение IUknown содержится в заголовочном файле UNKNWN.H:
interfaceIUknown
{
virtual HRESULT _stdcall
Queryinterface
(const IID&iid, void **ppv)=0;
virtual ULONG _StdcallAddRef()=0;
virtual ULONG _stdcall Release()=0;
};
Клиент вызывает первую функцию QueryInterface, чтобы определить, поддерживает ли компонент
некоторый интерфейс. Функции AddRefи Release представляют способ управления временем жизни
интерфейса.
Все интерфейсы COM наследуют IUknown и содержат указатели на QueryInterface, AddRef и Release в первых трех элементах своих vtbl, поэтому клиенту не требуется хранить
отдельный указатель на компонент; клиент работает только с указателями
интерфейсов.
Для получения указателя на IUknown используется функция CreateInstance вместо оператора new, которая создает компонент и возвращает указатель на IUknown:
Первый
параметр – идентификатор интерфейса, так называемая IID-структура. Пока мы будем рассматривать их как
константы, задающие интерфейс.
Второй параметр – адрес, по которому QueryInterface помещает указатель на искомый интерфейс.
Выводы
Использование виртуальных функций в базовом классе
является центральным моментом в проектировании COM-компонентов. Определение абстрактного класса
порождает таблицу, содержащую только открытые методы (т.е. интерфейс) класса.
Класс (IX) не содержит переменных-членов и функций реализации
объекта. Его единственная задача – порождение производного класса (СА) для
виртуальной реализации методов интерфейса компонента.
В технологии COM
доступ к компонентам обеспечивается только с помощью указателей на виртуальные
таблицы. Т.о. прямой доступ к конкретным данным компонента становится
невозможным. Ключевой концепцией COM является
использование виртуальных таблиц для доступа к функциональным возможностям
компонента, т.е. COM-интерфейс представляет собой
просто указатель на указатель виртуальной таблицы (vtbl) С++.