Выбрать главу

Если не использовалась технология асинхронных компонент, и издатель дождался конца процесса рассылки уведомлений, то он может проанализировать код возврата типа hresult, который может принимать одно из следующих значений:

♦ S_SUCCESS — уведомления были доставлены всем подписчикам,

♦ EVENT_S_SOME_SUBSCRIBERS_FAILD — код успешного в целом завершения рассылки, однако доставка уведомлений некоторым подписчикам завершилась неудачей. Заметим, что на этом этапе невозможно определить подписчиков, не получивших уведомлений,

♦ EVENT_E_ALL_SUBSCRIBERS_FAILD — неудача, никто из подписчиков не получил уведомления.

♦ EVENT_S_NOSUBSCRIBERS — операция завершилась успехом, но подписчики на данное событие отсутствуют.

Издатель, подписчик и подписка

Исходя из вышеизложенного, издателем может выступать любой компонент (программа), имеющий право активировать экземпляр событийного класса и вызвать некоторый его метод. Никакой специальной регистрации в подсистеме событий не требуется. Для использования универсального маршалинга (маршалинга библиотеки типов) необходимо зарегистрировать на машине издателя библиотеку типов событийного класса.

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

По поводу подписки следует заметить, что существует три ее типа:

• Постоянная

Постоянная подписка переживает перезагрузку компьютера. При использовании постоянной подписки при вызове некоторого метода событийного интерфейса издателем формируется новый экземпляр каждого подписчика, который обрабатывает переданный ему вызов и уничтожается после возврата из вызванного метода. Это обеспечивается тем, что подсистема событий имеет информацию о CLSID каждого подписчика и машине, на которой его следует активировать.

• Временная

Эта подписка сохраняется только на время жизни объекта — подписчика. В отличие от предыдущего случая, экземпляр класса подписчика активируется не подсистемой событий, а некоторым приложением. После этого выполняется подписка, в результате которой подсистема событий получает указатель на событийный интерфейс объекта-подписчика. После получения и обработки уведомления о событии объект-подписчик не уничтожается и может принимать новые уведомления.

• PerUser

Это вариант постоянной подписки, который можно использовать только в том случае, когда издатель и подписчик работают на одном компьютере. В записи о подписке этого типа хранится SID некоторого пользователя, в процессе которого был создан объект-подписчик. Подписка включается подсистемой событий только при входе пользователя с данным SID в систему и отключается при его выходе из системы.

Как и в случае регистрации событийного класса, зарегистрировать подписку может только администратор, используя программирование и/или Component Services. Каждая подписка на некоторое событие является объектом, хранимым в подсистеме событий. Подписаться можно на событийный интерфейс в целом (на все его методы) или на некоторый метод событийного интерфейса. Если необходимо подписаться на несколько методов событийного интерфейса (но не на все), нужно отдельно оформить подписку для каждого метода. Заметим, что подписчик должен реализовать все методы событийного интерфейса.

Начнем с программной регистрации подписки:

• Прежде всего формируется экземпляр реализованного в системе класса с идентификатором CLSID_CEventSubscription (объект подписки) и запрашивается указатель на интерфейс IEventSubscription этого класса.

• Интерфейс IEventSubscription используется для задания свойств объекта подписки:

♦ GUID регистрируемой подписки задается вызовом метода IEventSubscription:: put_SubscriptioniD (), где параметром является BSTR строка, задающая GUID подписки. Этот идентификатор должен быть уникален в данном сервисе событий,

♦ Имя регистрируемой подписки задается вызовом метода IEventSubscription:: put_SubscriptionName (), где параметром является BSTR строка, задающая название подписки. Это читаемая строка, предназначенная для администраторов,

♦ Уникальный идентификатор издателя задается вызовом метода IEventSubscription:: put_Publisherid (), где параметром является BSTR строка, задающая GUID издателя. Если эта информация не задана, то подписчик будет получать уведомления вне зависимости от того, какой издатель инициировал рассылку уведомлений через данный событийный класс,

♦ CLSID событийного класса задается вызовом метода IEventsSbscription:: put_EventClassiD (), где параметром является BSTR строка, задающая CLSID событийного класса, для получения уведомлений от которого и регистрируется данная подписка.

♦ Идентификатор событийного интерфейса, на который регистрируется подписка (а событийный класс может реализовывать несколько событийных интерфейсов) задается вызовом метода IEventsSbscription::putInterfaceiD, параметр типа BSTR задает GUID этого интерфейса.

♦ Метод iEventSubscription::putMethodName вызывается для задания метода событийного интерфейса, на который регистрируется подписка. Параметром является BSTR строка, задающая название метода,

♦ Вызов метода IEventSubscription::putSubscriberCLSID с параметром типа BSTR строка, задающим CLSID подписчика, используется в случае постоянной подписки. Данный CLSID будет использоваться подсистемой подписки для активации подписчика,

♦ Вызов метода IEventSubscription::putMashineName позволяет В виде BSTR строки задать имя машины, на которой следует в случае постоянной подписки активировать подписчика,

♦ Вызов метода IEventSubscription::putSubscriberInterfасе используется для организации временной подписки. В качестве параметра передается маршалированный указатель (типа IUnknown*) на интерфейс уже активированного подписчика, на который следует посылать уведомления,

♦ Вызов метода IEventВubscription::putPerUser позволяет задать подписку третьего типа, когда подписка действует только при входе в систему определенного пользователя — владельца подписки. Этот вариант используется только в том случае, когда подписчик активируется на на той же машине, где зарегистрирован событийный класс. Параметр типа BOOL включает или выключает это ограничение на подписку,

♦ Задать владельца подписки можно вызывая метод iEventSuscription::putOwnerSID, параметр типа BSTR задает Security ID владельца подписки.

• Формируется экземпляр реализованного в системе класса с идентификатором CLSID_CEventSystem и запрашивается указатель на его интерфейс IEventSystem.

• Вызывается метод Store этого интерфейса, которому в качестве первого параметра передается PROGID_EventSubscription, что указывает на то, что сохраняется именно объект-подписка, а в качестве второго параметра передается указатель на интерфейс IEventClass экземпляра класса с идентификатором CLSID_CEventSubscription, параметры которого настроены на регистрируемую подписку.

Фильтр на стороне издателя

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