Дональд Бокс - Сущность технологии СОМ. Библиотека программиста
- Название:Сущность технологии СОМ. Библиотека программиста
- Автор:
- Жанр:
- Издательство:Питер
- Год:2001
- Город:СПб
- ISBN:5-318-00058-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Дональд Бокс - Сущность технологии СОМ. Библиотека программиста краткое содержание
В этой книге СОМ исследуется с точки зрения разработчика C++. Написанная ведущим специалистом по модели компонентных объектов СОМ, она раскрывает сущность СОМ, помогая разработчикам правильно понять не только методы модели программирования СОМ, но и ее основу. Понимание мотивов создания СОМ и ее аспектов, касающихся распределенных систем, чрезвычайно важно для тех разработчиков, которые желают пойти дальше простейших приложений СОМ и стать по-настоящему эффективными СОМ-программистами. Показывая, почему СОМ для распределенных систем (Distributed СОМ) работает именно так, а не иначе, Дон Бокс дает вам возможность применять эту модель творчески и эффективно для ежедневных задач программирования.
Сущность технологии СОМ. Библиотека программиста - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
[uuid(75DA6458-DD9F-11d0-8C58-0080C73925BA),object]
interface ISoftwareConsumer : IUnknown {
HRESULT OnProductIsDone(void);
HRESULT OnProductWillBeLate([in] hyper nMonths);
}
При таком парном определении интерфейса должен существовать некий механизм для информирования объекта-программиста о том, что у клиента имеется реализация ISoftwareConsumer, с помощью которой он может получать уведомления от объекта-программиста об изменениях состояния. Одной из распространенных методик является определение IProgrammer таким образом, чтобы он имел явные методы, через которые клиенты могли бы связываться со своими объектами-потребителями (consumer object). Канонической формой этой идиомы является включение метода Advise:
interface IProgrammer : IUnknown {
HRESULT Advise ([in] ISoftwareConsumer *psc, [out] DWORD *pdwCookie);
: : :
посредством которого клиент подготавливает парный объект-потребитель, а программист возвращает DWORD для подтверждения связи. Затем этот DWORD можно было бы использовать в соответствующем методе Unadvise:
interface IProgrammer : IUnknown {
: : :
HRESULT Unadvise([in] DWORD dwCookie);
}
для того, чтобы сообщить объекту-программисту о прерывании связи. При использовании уникальных DWORD для представления связи программист-потребитель дизайн интерфейса позволяет произвольному числу потребителей независимо друг от друга соединяться с объектом и отсоединяться от него.
Если эти два метода имеются в интерфейсе IProgrammer, то реализация программиста может быть соединена с объектом-потребителем с помощью метода Advise
STDMETHODIMP Programmer::Advise(ISoftwareConsumer *pcs, DWORD *pdwCookie)
{
assert(pcs);
if (m_pConsumer != 0) // is there already a consumer?
// уже есть потребитель?
return E_UNEXPECTED;
(m_pConsumer = pcs)->AddRef();
// hold onto new consumer
// соединяемся с новым потребителем
*pdwCookie = DWORD(pcs);
// make up a reasonable cookie
// готовим подходящий маркер
return S_OK;
}
Соответствующая реализация метода Unadvise выглядела бы примерно так:
STDMETHODIMP Programmer::Unadvise(DWORD dwCookie)
{
// does the cookie correspond to the current consumer?
// соответствует ли маркер данному потребителю?
if (DWORD(m_pConsumer) != dwCookie)
return E_UNEXPECTED;
(m_pConsumer)->Release();
// release current consumer
// освобождаем текущего потребителя
m_pConsumer = 0;
return S_OK;
}
Взаимоотношения между программистом и потребителем показаны на рис. 7.7. Хотя в данной реализации в каждый момент предусмотрен только один потребитель, возможно, что более опытный программист смог бы оперировать несколькими потребителями одновременно, управляя динамическим массивом интерфейсных указателей из ISoftwareConsumer.

Имея приведенную выше реализацию, метод программиста StartHacking может теперь использовать потребителя для индикации готовности результата:
STDMETHODIMP Programmer::StartHacking (void)
{
assert(m_pConsumer);
// preemptively notify of lateness
// приоритетно сообщаем о задержке
HRESULT hr = m_Consumer->OnProductWillBeLate(3);
if (FAILED(hr))
return PROGRAMMER_E_UNREALISTICCONSUMER;
// generate some code
// генерируем некоторый код
extern char *g_rgpszTopFiftyStatements[];
for (int n = 0; n < 100000; n++)
printf(g_rgpszTopFiftyStatements[rand() % 50]);
// inform consumer of done-ness
// извещаем потребителя о выполнении
hr = m_pConsumer->OnProductIsDone();
return S_OK;
}
To обстоятельство, что реализация ISoftwareConsumer может принадлежать к другому апартаменту, чем объект-программист, не является существенным. На самом деле метод StartHacking может быть вызван из того апартамента, который содержит объект-потребитель, и в этом случае будет осуществлено повторное вхождение в апартамент вызывающей программы, что, в сущности, является синхронным обратным вызовом. В то время как эта реализация делает вложенные вызовы на объект-потребитель, объект-программист может также в будущем производить вызовы методов объекта-потребителя в любое время. Эта привилегия остается до тех пор, пока не последует вызов метода Unadvise, разрывающий соединение.
Поскольку интерфейсы IProgrammer и ISoftwareConsumer, вероятно, были созданы в тандеме для совместной работы, использование явного метода интерфейса IProgrammer для установления связи становится частью протокола при работе с объектами-программистами и является вполне целесообразным. Тот факт, что реализации программиста способны использовать один или несколько объектов-потребителей, может быть документирован как часть протокола интерфейса IProgrammer в порядке уточнения семантического контракта IProgrammer. Существуют, однако, сценарии, в которых интерфейсы совместной работы и обратного вызова разработаны так, что они находятся вне области видимости любого другого интерфейса. Ниже приведен пример такого интерфейса:
[uuid(75DA645D-DD0F-11d0-8C58-0080C73925BA),object ]
interface IShutdownNotify : IUnknown {
HRESULT OnObjectDestroyed([in] IUnknown *pUnk);
}
В этом интерфейсе предполагается, что разработчик IShutdownNotify заинтересован в получении сообщений о прекращении работы от других объектов. В данном определении, однако, не приведен механизм, с помощью которого эти заинтересованные стороны могли бы сообщить объектам, что они хотели бы быть уведомлены об уничтожении этого объекта. Как показано на рис. 7.8, одна из возможных стратегий осуществления этого состоит в определении второго (парного) интерфейса, который объекты могли бы реализовать:
[uuid(75DA645E-DD0F-11d0-8C58-0080C73925BA), object]
interface IShutdownSource : IUnknown {
HRESULT Advise([in] IShutdownNotify *psn, [out] DWORD *pdwCookie);
HRESULT Unadvise([in] DWORD dwCookie);
}

Данный интерфейс существует, однако, только для того, чтобы дать наблюдателям (observers) возможность соединить свои интерфейсы IShutdownNotify с объектом. Если имеется большое число типов интерфейсов обратного вызова, то необходимо определить столь же большое число соответствующих интерфейсов только для управления соединением. Ясно, что должен существовать более общий механизм: вхождение в точках стыковки.
Точки стыковки являются идиомой СОМ, предназначенной для регистрации связи интерфейсов обратного вызова с объектом и ее отмены. Точки стыковки не являются необходимыми для создания сетей из объектов с большим количеством соединений. К тому же точки стыковки не обеспечивают двунаправленных соединений. Вместо этого идиома точек стыковки выражает общую концепцию регистрации экспортируемых интерфейсов как небольшого числа интерфейсов стандартной инфраструктуры. Наиболее фундаментальным из этих интерфейсов является IConnectionPoint:
[object, uuid(B196B286-BAB4-101A-B69C-00AA00341D07)]
interface IConnectionPoint : IUnknown {
// which type of interface can be connected
// какой тип интерфейса можно присоединить
HRESULT GetConnectionInterface( [out] IID * pIID);
// get a pointer to identity of «real» object
// получаем указатель на копию «реального» объекта
HRESULT GetConnectionPointContainer([out] IConnectionPointContainer ** ppCPC);
// hold and use pUnkSink until notified otherwise
// сохраняем и используем pUnkSink, пока не объявлено другое
Читать дальшеИнтервал:
Закладка: