Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Материалы к лекциям COM.doc
Скачиваний:
4
Добавлен:
18.04.2019
Размер:
880.64 Кб
Скачать

8.3. Интерфейс iUnknown и наследование интерфейсов

8.3.1. Интерфейс iUnknown

Наследование в COM не означает повторного использования кода, как это обычно бывает в объектно-ориентированных языках программирования. Оно означает только, что ассоциированный с интерфейсом контракт наследуется в манере чисто виртуального базового класса С++ и изменяется добавлением новых методов или дальнейшим уточнением допустимого использования методов. В COM отсутствует избирательное наследование. Если один интерфейс наследует от другого, он включает все методы, определяемые другим интерфейсом.

Наследование в стандартных COM-интерфейсах используется довольно скупо. Все интерфейсы должны быть унаследованы от интерфейса IUnknown. IUnknown содержит три жизненно важных для COM метода: QueryInterface, AddRef и Release. Все COM-объекты должны реализовать интерфейс IUnknown, поскольку он обеспечивает возможность получать поддерживаемые объектом интерфейсы с помощью QueryInterface, и управлять сроком жизни объекта через AddRef и Release.

Интерфейс IUnknown инкапсулирует 2 операции:

  1. Управлением временем жизни объекта;

  2. Навигация между объектами.

Высокоуровневые средства разработки (такие, как VB) полностью скрывают реализацию IUnknown, облегчая тем самым работу программиста. Низкоуровневые средства разработки (например, VC++) напротив, дают полный доступ к исходным текстам, реализующим IUnknown. На C++ или Delphi можно самостоятельно реализовать IUnknown. Но проще воспользоваться стандартными реализациями. Для C++ самый удобный, но в тоже время гибкий и очень компактный способ реализации IUnknown – воспользоваться библиотекой ATL (Active Template Library). ATL – это библиотека, главным образом состоящая из набора шаблонов C++. ATL упрощает работу с COM, предоставляя реализации для многих стандартных интерфейсов. Эта библиотека входит в поставку MS VC++ и Borland C++ Builder. В сочетании с визуальными средствами разработки этих сред ATL позволяет очень быстро создавать сложные приложения, базирующиеся на COM.

8.3.2. Получение указателя на интерфейс – QueryInterface

Метод QueryInterface (полный вид – HResult QueryInterface (REEFID riid, void ** ppv)) предоставляет интерфейс IUnknown::QueryInterface COM-объекта, который пытается получить указатель определенного интерфейса. Использование QueryInterface для COM-объекта аналогично выполнению операции приведения в управляемом коде. Вызов объекта с этим методом приводит к увеличению счетчика ссылок для указателя интерфейса до возвращения указателя. Каждый раз по окончании работы с указателем для уменьшения значения счетчика ссылок следует использовать Marshal.Release.

Если возвращаемое значение равно NOERROR, это означает что запрашиваемый интерфейс существует.

Основные правила вызова функции QueryInterface:

  1. Любой вызов QueryInterface через любой интерфейс объекта должен всегда возвращать одну и ту же величину;

  2. После создания объект должен поддерживать все свои интерфейсы;

  3. Любая QueryInterface:

  • Рефлективна – спецификация СОМ требует, чтобы запрос QueryInterface через интерфейсный указатель всегда достигал цели, если запрошенный тип соответствует типу указателя, с помощью которого произведен запрос (рис. 8.1). Это означает, что QI(A)->A всегда должен быть верным.

Рис. 8.1 Демонстрация рефлективности QueryInterface

  • Симметрична – спецификация СОМ требует, чтобы, если запрос QueryInterface на интерфейс B удовлетворяется через интерфейсный указатель типа A, то запрос QueryInterface на интерфейс A того же самого объекта через результирующий интерфейсный указатель типа В всегда был успешным (рис. 8.2). Это значит, что если верно QI(A)->B, то также должно быть верным QI(QI(A)->B)->A.

Рис. 8.2 Демонстрация симметричности QueryInterface

  • Транзитивна – спецификация СОМ требует также, чтобы, если запрос QueryInterface на интерфейс В удовлетворяется через интерфейсный указатель типа A, а второй запрос QueryInterface на интерфейс C удовлетворяется через указатель типа В, то запрос QueryInterface на интерфейс C через исходный указатель типа A был бы также успешным (рис. 8.3). Это означает, что если верно QI(QI(A)->B)->C, то должно быть верным и QI(A)->C.

Рис. 8.2 Демонстрация транзитивности QueryInterface