Интернет-журнал 'Домашняя лаборатория', 2007 №6 - Вязовский
Шрифт:
Интервал:
Закладка:
• Регистрация событийного класса в подсистеме событий
Прежде всего отметим, что в СОМ+ не реализована распределенность базы данных подсистемы событий. Это означает, что после выбора машины, на которой в ее подсистеме событий будет зарегистрирован событийный класс, издатель соответствующего события должен активировать экземпляр событийного класса именно на этой машине. В подсистеме событий именно этой машины должны регистрироваться и подписчики на события, представленные данным событийным классом.
При регистрации событийного класса можно использовать и
Component Services и стандартные интерфейсы для работы с подсистемой событий. Рассмотрим вначале использование стандартных интерфейсов для работы с подсистемой событий:
♦ Прежде всего формируется экземпляр реализованного в системе класса с идентификатором CLSID_CEventClass и запрашивается указатель на интерфейс IEventClass этого класса.
♦ Интерфейс IEventClass используется для задания свойств класса CLSID_CEventClass, которые должны определить регистрируемый событийный класс:
— CLSID регистрируемого событийного класса задается вызовом метода IEventClass:: put_EventClassID (), где параметром является BSTR строка, задающая CLSID событийного класса.
— ProgID регистрируемого событийного класса задается вызовом метода IEventClass:: put_EventClassName (), где параметром является BSTR строка, задающая ProgID событийного класса.
— IID событийного интерфейса регистрируемого событийного класса задается вызовом метода IEventClass::put_FiringInterfaceID (), где параметром является BSTR строка, задающая IID событийного интерфейса.
Для преобразования GUID в BSTR строку можно использовать функцию StringFromIID.
♦ Формируется экземпляр реализованного в системе класса с идентификатором CLSID_CEventSystem и запрашивается указатель на его интерфейс IEventSystem. Данный интерфейс предоставляет методы для добавления, удаления и извлечения событийных классов и подписок из базы данных подсистемы событий.
♦ Вызывается метод store этого интерфейса, которому в качестве первого параметра передается PROGID_EventClass, что указывает на то, что сохраняется именно событийный класс, а в качестве второго параметра передается указатель на интерфейс IEventClass экземпляра класса с идентификатором CLSID_CEventClass, параметры которого настроены на регистрируемый событийный класс.
Событийный класс может конфигурироваться и с помощью Component Services. При этом можно задавать как специфические именно для событийного класса настройки, так и настройки, применимые ко всем СОМ+ компонентам:
♦ Асинхронность событийного класса
Если событийный класс сконфигурирован как асинхронный (Queued Component), то издатель, активируя экземпляр событийного класса как асинхронный (с помощью моникера queue), сможет не дожидаться отправки уведомлений подсистемой событий всем подписчикам, а перейти к выполнению других функций. Здесь уместно заметить, что разумно сконфигурировать как асинхронные и всех подписчиков. В этом случае подсистема событий не будет иметь проблем с подписчиками, которые должны быть активированы на машинах, к которым временно нет доступа. Кроме того, это даст возможность администратору машины, на которой активируется подписчик, управлять процессом получения уведомлений, выделяя для этого удобное время.
♦ Поддержка транзакций событийным классом
В ряде случае удобно конфигурировать и событийный класс и всех его подписчиков как поддерживающих транзакции. Тогда издатель может инициировать транзакцию, исход которой определяется всеми подписчиками.
♦ Безопасность
Очевидна роль системы безопасности в распределенном приложении. Подсистема событий вносит сюда свою специфику. Прежде всего заметим, что регистрация событийного класса и подписок на соответствующие события доступна только администраторам машины, на которой выполняется регистрация. Такая политика повышает уровень безопасности, но и накладывает дополнительную нагрузку на администраторов.
Издатель, событийный класс и подписчик могут использовать все возможности, предлагаемые системой безопасности в СОМ+. Например, подписчик может выяснить, является ли издатель события тем, за кого себя выдает.
Среди специфических именно для событийного класса настроек имеется возможность разрешить подписчикам, скомпонованным в виде библиотечных приложений, выполняться в адресном пространстве издателя. Такой выбор сократит время уведомления подписчиков, но понизит уровень безопасности, т. к. в этом случае подписчик сможет выполнять различные вызовы от лица издателя.
♦ Параллельная рассылка уведомлений
По умолчанию подсистема событий рассылает уведомления всем подписчикам последовательно, в некотором заранее не определенном порядке. При этом возникает следующая проблема. Вызов подписчика сводится к вызову некоторого реализованного им метода событийного интерфейса. Какова реализация этого метода, как долго этот метод будет выполняться — подсистеме событий неизвестно. Но передача уведомления следующему подписчику в данном случае будет выполнена только после завершения передачи уведомления предыдущему подписчику. Это означает, что подсистема событий не может гарантировать временной интервал, в рамках которого все подписчики получат уведомления.
Потребовав параллельную рассылку уведомлений для данного класса событий, администратор просит подсистему событий по возможности рассылать уведомления параллельно, из разных потоков.
Более кардинальное решение проблемы связано с использованием фильтра на стороне издателя, что будет рассмотрено позднее.
♦ Идентификатор издателя
Событийному классу можно приписать уникальный идентификатор издателя. Это позволяет подписываться на события, распространение которых инициируется конкретным издателем.
Имеется еще один важный параметр класса событий, задание которого возможно только программным путем (используя административные компоненты для работы с СОМ+ каталогом) после регистрации событийного класса. Это свойство событийного класса MuitiInterfacePubiisherFilterCLSID. Данное свойство задает CLSID специального класса — фильтра, который на стороне издателя может регулировать рассылку уведомлений подписчикам. Данный фильтр будет обсуждаться позднее.
• Активация экземпляра событийного класса и инициализация рассылки уведомлений Активация экземпляра событийного класса выполняется издателем, желающим инициировать рассылку уведомлений о наступлении некоторого события. Издатель формирует экземпляр событийного класса, вызывая, например, функцию CoCreateInstance. Далее, получив указатель на событийный интерфейс данного событийного класса, он вызывает некоторый метод этого интерфейса, инициируя тем самым рассылку уведомлений всем подписчикам. Особенностью процесса активации экземпляра событийного класса является то, что подсистема событий автоматически синтезирует реализацию событийного интерфейса, обеспечивая активацию подписчиков и вызов соответствующего реализованного каждым подписчиком метода событийного интерфейса. Заметим, что в процесс рассылки уведомлений могут вмешаться два фильтра — фильтр со стороны издателя и фильтр со стороны подписчика.
Если не использовалась технология асинхронных компонент, и издатель дождался конца процесса рассылки уведомлений, то он может проанализировать код возврата типа hresult, который может принимать одно из следующих значений:
♦ S_SUCCESS — уведомления были доставлены всем подписчикам,
♦ EVENT_S_SOME_SUBSCRIBERS_FAILD — код успешного в целом завершения рассылки, однако доставка уведомлений некоторым подписчикам завершилась неудачей. Заметим, что на этом этапе невозможно определить подписчиков, не получивших уведомлений,
♦ EVENT_E_ALL_SUBSCRIBERS_FAILD — неудача, никто из подписчиков не получил уведомления.
♦ EVENT_S_NOSUBSCRIBERS — операция завершилась успехом, но подписчики на данное событие отсутствуют.
Издатель, подписчик и подписка
Исходя из вышеизложенного, издателем может выступать любой компонент (программа), имеющий право активировать экземпляр событийного класса и вызвать некоторый его метод. Никакой специальной регистрации в подсистеме событий не требуется. Для использования универсального маршалинга (маршалинга библиотеки типов) необходимо зарегистрировать на машине издателя библиотеку типов событийного класса.
Подписчиком является обычный