-->

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

На нашем литературном портале можно бесплатно читать книгу Сущность технологии СОМ. Библиотека программиста, Бокс Дональд-- . Жанр: Программирование. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале bazaknig.info.
Сущность технологии СОМ. Библиотека программиста
Название: Сущность технологии СОМ. Библиотека программиста
Дата добавления: 16 январь 2020
Количество просмотров: 277
Читать онлайн

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

Сущность технологии СОМ. Библиотека программиста - читать бесплатно онлайн , автор Бокс Дональд

В этой книге СОМ исследуется с точки зрения разработчика C++. Написанная ведущим специалистом по модели компонентных объектов СОМ, она раскрывает сущность СОМ, помогая разработчикам правильно понять не только методы модели программирования СОМ, но и ее основу. Понимание мотивов создания СОМ и ее аспектов, касающихся распределенных систем, чрезвычайно важно для тех разработчиков, которые желают пойти дальше простейших приложений СОМ и стать по-настоящему эффективными СОМ-программистами. Показывая, почему СОМ для распределенных систем (Distributed СОМ) работает именно так, а не иначе, Дон Бокс дает вам возможность применять эту модель творчески и эффективно для ежедневных задач программирования.

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала

1 ... 51 52 53 54 55 56 57 58 59 ... 118 ВПЕРЕД
Перейти на страницу:

Имея прототип функции, приведенный выше, класс 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);

// 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);

// composite to map distinguished IUnknown vptr to

// non-delegating InternalXXX routines in main object

// композит для преобразования определенного vptr IUnknown

// в неделегирующие подпрограммы InternalXXX в главном

// объекте

class XNDUnknown : public IUnknown

{ Car* This()

{

return (Car*)((BYTE*)this – offsetof(Car, m_innerUnknown));

}

STDMETHODIMP QueryInterface(REFIID r, void**p)

{

return This()->InternalQueryInterface(r,p);

}

STDMETHODIMP_(ULONG) AddRef(void)

{

return This()->InternalAddRef();

}

STDMETHODIMP_(ULONG) Release(void)

{

return This()->InternalRelease();

}

};

XNDUnknown m_innerUnknown;

// composite instance

// экземпляр композита };

Двоичное размещение этого объекта показано на рис. 4.8. Методы делегирования класса чрезвычайно просты:

STDMETHODIMP Car::QueryInterface(REFIID riid, void **ppv) { return m_pUnkOuter->QueryInterface(riid, ppv); }

STDMETHODIMP_(ULONG) Car::AddRef(void) { return m_pUnkOuter->AddRef(); }

STDMETHODIMP_(ULONG) Car::Release (void) { return m_pUnkOuter->Release(); }

Сущность технологии СОМ. Библиотека программиста - fig4_8.jpg

Эти подпрограммы являются версиями, которые будут заполнять таблицы vtbl всех интерфейсов объекта, так что какой бы интерфейс клиент ни получил, методы IUnknown всегда передают функции основной идентификационной единице объекта.

Для того чтобы объект можно было использовать в обоих сценариях – агрегирования и автономном – разработчик объекта должен установить свой элемент данных m_pUnkOuter так, чтобы в случае автономного режима он указывал на собственный неделегирующий IUnknown:

Car::Car(IUnknown *pUnkOuter)

{

if (pUnkOuter)

// delegate to pUnkOuter

// делегируем в pUnkOuter

m_pUnkOuter = pUnkOuter;

else // delegate to non-delegating self

// делегируем неделегирующему себе m_pUnkOuter = &m_innerUnknown;

}

Разработчик обеспечивает то, что в обоих случаях m_pUnkOuter указывает на нужную для данного объекта реализацию QueryInterface, AddRef и Release.

Обычные неделегирующие реализации QueryInterface, AddRef и Release являются вполне правильными и предсказуемыми:

STDMETHODIMP Car::InternalQueryInterface(REFIID riid, void **ppv)

{

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

else if (riid = IID_IVehicle) *ppv = static_cast<IVehicle*>(this);

else if (riid == IID_ICar) *ppv = static_cast<ICar*>(this);

else return (*ppv = 0), E_NOINTERFACE;

((IUnknown*)*ppv)->AddRef();

return S_OK;

}

STDMETHODIMP_(ULONG) Car::InternalAddRef(void)

{

return InterlockedIncrement(&m_cRef);

}

STDMETHODIMP_(ULONG) Car::InternalRelease(void)

{

ULONG res = InterlockedDecrement(&m_cRef);

if (res == 0) delete this;

return res;

}

Единственной отличительной особенностью этих трех методов (кроме их имен) является то, что InternalQueryInterface при запросе IUnknown возвращает указатель на неделегирующую Unknown. Это просто требование Спецификации СОМ, которого следует придерживаться.

И наконец, подпрограмму создания Car требуется модифицировать для поддержки агрегирования:

STDMETHODIMP CarClass::CreateInstance(IUnknown *punk0uter, REFIID riid, void **ppv)

{

// verify that aggregator only requests IUnknown as

// initial interface

// проверяем, что агрегатор только запрашивает IUnknown как

// начальный интерфейс

if (pUnkOuter != 0 && riid != IID_IUnknown)

1 ... 51 52 53 54 55 56 57 58 59 ... 118 ВПЕРЕД
Перейти на страницу:
Комментариев (0)
название