- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Сущность технологии СОМ. Библиотека программиста - Дональд Бокс
Шрифт:
Интервал:
Закладка:
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, пока не объявлено другое
HRESULT Advise([in] IUnknown * pUnkSink, [out] DWORD * pdwCookie);
// stop holding/using the pointer associated with dwCookle
// прекращаем хранение/использование указателя, связанного с dwCookie
HRESULT Unadvise([in] DWORD dwCookie);
// get information about currently held pointers
// получаем информацию об имеющихся в данный момент указателях
HRESULT EnumConnections([out] IEnumConnections ** ppEnum);
}
Как показано на рис. 7.9, объекты представляют отдельную реализацию этого интерфейса каждому типу интерфейса, который может быть использован объектом в качестве интерфейса обратного вызова. Ввиду того, что IConnectionPoint не выставлен как часть единицы идентификации объекта, он не может быть обнаружен посредством QueryInterface. Вместо этого в СОМ предусмотрен второй интерфейс, который выставлен как часть единицы идентификации объекта, которая позволяет клиентам запрашивать реализацию IConnectionPoint, соответствующую отдельному типу интерфейса обратного вызова:
[object,uuid(B196B284-BAB4-101A-B69C-00AA00341D07)]
interface IConnectionPointContainer : IUnknown {
// get all possible IConnectionPoint implementations
// получаем все возможные реализации IConnectionPoint
HRESULT EnumConnectionPoints([out] IEnumConnectionPoints ** ppEnum);
// get the IConnectionPoint implementation for riid
// получаем реализацию IConnectionPoint для riid
HRESULT FindConnectionPoint([in] REFIID riid, [out] IConnectionPoint ** ppCP);
}
Как показано на рис. 7.9, каждая реализация IConnectionPoint выставляется из отдельной СОМ-единицы идентификации.
С учетом вышеупомянутых определений интерфейса клиент мог бы связать свою реализацию IShutdownNotify с объектом следующим образом:
HRESULT HookupShutdownCallback(IUnknown *pUnkObject,
IShutdownNotify *pShutdownNotify,
DWORD &rdwCookie)
{
IConnectionPointContainer *pcpc = 0;
HRESULT hr = pUnkObject->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc);
if (SUCCEEDED(hr)) {
IConnectionPoint *pcp = 0;
hr =pcpc->FindConnectionPoint(IID_IShutdownNotify,&pcp);
if (SUCCEEDED(hr)) {
hr = pcp->Advise(pShutdownNotify, &rdwCookie);
pcp->Release();
}
pcpc->Release();
}
}
Соответствующий код для разрыва связи выглядит так:
HRESULT TeardownShutdownCallback(IUnknown *pUnkObject, DWORD dwCookie)
{
IConnectionPointContainer *pcpc = 0;
HRESULT hr = pUnkObject->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc);
if (SUCCEEDED(hr)) {
IConnectionPoint *pcp = 0;
hr =pcpc->FindConnectionPoint(IID_IShutdownNotify,&pcp);
if (SUCCEEDED(hr)) {
hr = pcp->Unadvise(dwCookie);
pcp->Release();
}
pcpc->Release();
}
}
Отметим, что в обоих примерах клиент использует метод IConnectionPointContainer::FindConnectionPoint для вызова из объекта его IShutdownNotify-реализации IConnectionPoint. Если объект отклоняет вызов FindConnectionPoint, это говорит о том, что он не понимает семантику интерфейса IShutdownNotify. Это оберегает пользователя от прикрепления произвольных интерфейсов обратного вызова к объекту без полного согласия на это разработчика объекта.
Как и в случае с IUnknown, реализации IConnectionPointContainer и IConnectionPoint в значительной степени типичны. Объекту C++ требуется отдельная единица идентификации СОМ для каждого типа экспортируемого интерфейса, который он предполагает поддерживать. Одна из методик реализации ConnectionPoint состоит в использовании того варианта методики вложения класса/композиции, которая учитывает различия в отношениях тождественности: