Чтение онлайн

на главную - закладки

Жанры

Сущность технологии СОМ. Библиотека программиста
Шрифт:

[object, uuid(753A8A60-A7FF-11d0-8C30-0080C73925BA)] interface IBicycle : IVehicle

{

HRESULT GetHandlebar([out,retval] IHandlebar **pph);

HRESULT GetWheels([out] IWheel **ppwFront, [out] IWheel **ppwBack);

}

Реализация Bicycle могла бы тогда просто возвращать указатели на свои подобъекты:

STDMETHODIMP Bicycle::GetHandlebar(IHandlebar **pph)

{

if (*pph = m_pHandlebar) (*pph)->AddRef;

return S_OK;

}

STDMETHODIMP Bicycle::GetWheels(IWheel **ppwFront, IWheel **ppwBack)

{

if (*ppwFront = m_pFrontWheel) (*ppwFront)->AddRef;

if (*ppwBack = m_pBackWheel) (*ppwBack)->AddRef;

return S_OK;

}

При

использовании данной технологии клиент по-прежнему получает прямой доступ к подобъектам. Однако поскольку указатели получены через явные методы, а не через QueryInterface, то между различными компонентами не существует никаких идентификационных отношений.

Несмотря на этот пример, все же остаются сценарии, где желательно обеспечить реализацию интерфейса, которая могла бы быть внедрена в идентификационную единицу другого объекта. Чтобы осуществить это, в СОМ-агрегировании требуется, чтобы внутренний объект (агрегируемый) уведомлялся во время его создания, что он создается как часть идентификационной единицы другого объекта. Это означает, что создающая функция (creation function), обычно используемая для создания объекта, требует один дополнительный параметр: указатель IUnknown на идентификационную единицу, которой агрегирующий объект должен передать функции в ее методы QueryInterface, AddRef и Release. Покажем определение метода CreateInstance интерфейса IClassFactory:

HRESULT CreateInstance([in] Unknown *pUnkOuter, [in] REFIID riid, [out, iid_is(riid)] void **ppv);

Этот метод (и соответствующие API-функции CoCreateInstanceEx и CoCreateInstance) перегружен с целью поддержки создания автономных (stand-alone ) объектов и агрегатов. Если вызывающий объект передает нулевой указатель и качестве первого параметра CreateInstance (pUnkOuter ), то результирующий объект будет автономной идентификационной единицей самого себя. Если же вызывающий объект передает в качестве первого параметра ненулевой указатель, то результирующий объект будет агрегатом с идентификационной единицей, ссылка на которую содержится в pUnkOuter. В случае агрегации агрегат должен переадресовывать все запросы QueryInterface, AddRef и Release непосредственно и безусловно на pUnkOuter. Это необходимо для обеспечения идентификации объекта.

Имея прототип функции, приведенный выше, класс CarBoat после небольшой модификации будет удовлетворять правилам агрегации:

CarBoat::CarBoat(void) : m_cRef(0)

{

// need to pass identity of self to Create routine

// to notify car object it 1s an aggregate

// нужно передать свою идентификацию подпрограмме

// Create для уведомления объекта car, что он – агрегат

HRESULT hr = CoCreateInstance(CLSID_Car, this, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkCar);

assert(SUCCEEDED(hr));

}

Реализация CarBoat QueryInterface просто переадресовывает запрос ICar внутреннему агрегату:

STDMETHODIMP CarBoat::QueryInterface(REFIID riid, void **ppv)

{

if (riid == IID_IUnknown) *ppv = static_cast<IUnknown*>(this);

else if (riid == IID_ICar)

// forward request…

//

переадресовываем запрос…

return m_pUnkCar->QueryInterface(riid, ppv);

else if (riid == IID_IBoat)

:

:

:

Теоретически это должно работать, так как агрегат будет всегда переадресовывать любые последующие запросы QueryInterface обратно главному объекту, проводя таким образом идентификацию объекта.

В предыдущем сценарии метод CreateInstance класса Car возвращает внешнему объекту указатель интерфейса, наследующего IUnknown. Если бы этот интерфейсный указатель должен был просто делегировать вызовы функций интерфейсу IUnknown внешнего объекта, то невозможно было бы: 1) уведомить агрегат, что он больше не нужен; 2) запросить интерфейсные указатели при выделении их клиентам главного объекта. На деле результатом приведенной выше реализации QueryInterface будет бесконечный цикл, поскольку внешний объект делегирует функции внутреннему, который делегирует их обратно внешнему.

Для решения этой проблемы необходимо сделать так, чтобы начальный интерфейсный указатель, который возвращается внешнему объекту, не делегировал вызовы реализации IUnknown внешнего объекта. Это означает, что объекты, поддерживающие СОМ– агрегирование, должны иметь две реализации IUnknown. Делегирующая, то есть передающая функции, реализация переадресовывает все запросы QueryInterface, AddRef и Release внешней реализации. Это и есть реализация по умолчанию, на которую ссылаются таблицы vtbl всех объектов, и это именно та версия, которую видят внешние клиенты. Объект должен также иметь неделегирующую реализацию IUnknown, которая выставляется только агрегирующему внешнему объекту.

Имеется несколько возможностей обеспечить две различные реализации IUnknown от одного объекта. Самый прямой путь [1]это использование композиции и элемента данных для реализации неделегирующих методов IUnknown. Ниже показана реализация Car, поддающаяся агрегации:

class Car : public ICar

{

LONG m_cRef;

IUnknown *m_pUnk0uter;

public: Car(IUnknown *pUnk0uter);

1 Автор однажды уверовал, что раскраска (coloring) методов является наилучшим способом для обеспечения двух реализации IUnknown. Со временем способ, приведенный в данной книге, доказал свою большую пригодность и не меньшую эффективность.

// non-delegating IUnknown methods

// неделегирующие методы

IUnknown STDMETHODIMP InternalQueryInterface(REFIID, void **);

STDMETHODIMP (ULONG) InternalAddRef(void);

STDMETHODIMP_(ULONG) InternalRelease(void);

// delegating IUnknown methods

// делегирующие методы IUnknown

STDMETHODIMP QueryInterface(REFIID, void **);

STDMETHODIMP_(ULONG) AddRef(void);

STDMETHODIMP_(ULONG) Release(void);

STDMETHODIMP GetMaxSpeed(*long *pn);

STDMETHODIMP Brake(void);

Поделиться:
Популярные книги

Родословная. Том 2

Ткачев Андрей Юрьевич
2. Линия крови
Фантастика:
городское фэнтези
аниме
фэнтези
5.00
рейтинг книги
Родословная. Том 2

Волхв

Земляной Андрей Борисович
3. Волшебник
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волхв

Возвышение Меркурия. Книга 4

Кронос Александр
4. Меркурий
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Возвышение Меркурия. Книга 4

Отморозок 4

Поповский Андрей Владимирович
4. Отморозок
Фантастика:
попаданцы
фантастика: прочее
5.00
рейтинг книги
Отморозок 4

Газлайтер. Том 14

Володин Григорий Григорьевич
14. История Телепата
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Газлайтер. Том 14

АллатРа

Новых Анастасия
Научно-образовательная:
психология
история
философия
обществознание
физика
6.25
рейтинг книги
АллатРа

Золотой ворон

Сакавич Нора
5. Все ради игры
Фантастика:
зарубежная фантастика
5.00
рейтинг книги
Золотой ворон

Курсант: Назад в СССР 4

Дамиров Рафаэль
4. Курсант
Фантастика:
попаданцы
альтернативная история
7.76
рейтинг книги
Курсант: Назад в СССР 4

Все ведьмы – стервы, или Ректору больше (не) наливать

Цвик Катерина Александровна
1. Все ведьмы - стервы
Фантастика:
юмористическая фантастика
5.00
рейтинг книги
Все ведьмы – стервы, или Ректору больше (не) наливать

Мужчина моей судьбы

Ардова Алиса
2. Мужчина не моей мечты
Любовные романы:
любовно-фантастические романы
8.03
рейтинг книги
Мужчина моей судьбы

Случайная жена для лорда Дракона

Волконская Оксана
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Случайная жена для лорда Дракона

Кровь на клинке

Трофимов Ерофей
3. Шатун
Фантастика:
боевая фантастика
попаданцы
альтернативная история
6.40
рейтинг книги
Кровь на клинке

Барон устанавливает правила

Ренгач Евгений
6. Закон сильного
Старинная литература:
прочая старинная литература
5.00
рейтинг книги
Барон устанавливает правила

Кротовский, вы сдурели

Парсиев Дмитрий
4. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
рпг
5.00
рейтинг книги
Кротовский, вы сдурели