Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Реализация событий COM+ в среде Delphi

Введение

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

GUI пользователя должен уметь обрабатывать различное количество событий, например, таких как: нажатие на кнопку мыши, перемещение мыши по экрану и т.д. Приблизительно так же может возникнуть потребность обрабатывать события внутри объектов COM. В данной статье мы рассмотрим принцип работы свободно связанных событий и создадим наглядное приложение для демонстрации использования такого типа событий в COM+. (Для более детальной информации о события в COM+ смотрите статью А.Новика «Система поддержки событий COM+» на сайте журнала «Клиент-Сервер»).

Что такое свободно связанные события? Понятие «Издатель-Подписчик»

До появления COM+, модель COM поддерживала систему событий, реализованную через интерфейс IConnectionPointContainer. Это жестко связанные события. (В данной статье, мы не будем рассматривать реализацию этого подхода). В COM+ появилось новое понятие: СВОБОДНО СВЯЗАННЫЕ СОБЫТИЯ (Loosely coupled events - LCE), разработанные для удовлетворения потребностей распределенных вычислений.

В COM+ Инициатор события (Издатель) и потребитель (Подписчик) свободно связаны.

Информация от различных издателей хранится в каталоге COM+, а подписчики указывают, какую информацию они хотят получать, регистрируясь в каталоге.

Архитектура событий в COM+

Для реализации свободно связанных событий вы должны создать компонент EventClass, который будет зарегистрирован в каталоге COM+. Подписчики вызываются объектом события, который определяет и активизирует объекты, подписанные на него.

Следует различать виды подписки. Существует временная и постоянная подписки:

Временная подписка (transient)
создается средствами административного API. Для более детальной информации можно обратиться в MSDN. Управлять жизненным циклом такой подписки нужно программными средствами. А не средствами ComponentServices.
Постоянная подписка (persistent)
создается средствами ComponentServices. Такая подписка в состоянии пережить перезапуск системы.

Фильтрация существует только в системе COM+. Такой возможности нет в системе жестко связанных событий. Её суть мы рассмотрим дальше, при более детальном изучении примера.

Пример реализации компонента EventClass

Допустим, у нас существует задача на базе существующей системы, функционирующей в среде COM+, реализовать систему ведения собственно журнала событий в текстовом файле. Для начала нам нужно реализовать компонент EventClass, о котором речь шла выше. Он будет представлять собой пустую заглушку для подписчика. Именно через него будут запускаться наши подписчики в каталоге COM+.

Когда компонент-издатель будет создавать событие, компонент EventClass передаст все входящие параметры события и активизирует всех подписчиков.

Важно! Метод события может содержать только входные параметры [in]. Выходным может быть только результирующий тип HRESULT, принятый в COM для определения статуса завершения S_OK, в результате удачи или E_FAIL, в результате неудачи выполнения метода.

Запустим среду Delphi, создадим простую ActiveX библиотеку и поместим в неё объект автоматизации (Automation Object). Определим нумератор типов ошибок и создадим интерфейс ISysLogEvent с методом ReportLog.


type

LogMessageTypes = TOleEnum;

const
  lmtInformation = $00000000;
  lmtWarning = $00000001;
  lmtError = $00000002;
  lmtFatal = $00000003;
  lmtDebug = $00000004;
  lmtUnknown = $00000005;

type
  TSysLogEvent = class(TAutoObject, ISysLogEvent)
  protected
  { Protected declarations }
    procedure ReportLog(enMsgType: LogMessageTypes; const strUserName,
      strModuleName, strMsgText: WideString); safecall;
end;

В разделе Implementation создадим заглушку метода для EventClass:


implementation

uses
  ComServ;

procedure TSysLogEvent.ReportLog(enMsgType: LogMessageTypes;
  const strUserName, strModuleName, strMsgText: WideString);
begin

// Event class methods are not implemented.

end;

initialization

TAutoObjectFactory.Create(ComServer, TSysLogEvent, Class_SysLogEvent,
  ciMultiInstance, tmApartment);

end.

На этом закончим. Остается зарегистрировать заглушку в нашем приложении COM+. Если приложение не создано, создайте его через средства ComponentServices.

Пример реализации Объекта-подписчика

После регистрации компонента EventClass создадим компонент-подписчик:

  1. Точно так же, как при создании компонента EventClass создадим библиотеку и объект автоматизации. Немного будет отличаться наполнение реализации методов и метод регистрации.
  2. Создадим интерфейс с методом, аналогичным методу интерфейса ILogEvent – ISysLog

Важно! Не забудьте подключить в вашу библиотеку типов зарегистрированную в ComponentServices библиотеку с заглушкой EventClass и укажите интерфейс ISysLogEvent в разделе Implements.

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


unit SysLogUnit;

interface

uses
  ComObj, ActiveX, SystemLogger_TLB, StdVcl, LogEvent_TLB, Dialogs;

type
  TSysLog = class(TAutoObject, ISysLog, ISysLogEvent)
  protected
    { Protected declarations }
    procedure ReportLog(enMsgType: LogMessageTypes; const strUserName,
      strModuleName, strMsgText: WideString); safecall;
end;

implementation

uses
  ComServ, SysUtils;

procedure TSysLog.ReportLog(enMsgType: LogMessageTypes; const strUserName,
  strModuleName, strMsgText: WideString);
begin
  ShowMessage('MessageType : '+IntToStr(enMsgtype)+#10#13+
  'ModuleName : '+strModuleName+#10#13+
  'UserName : '+strUserName+#10#13+
  'TextMessage : '+strMsgText);
end;

initialization
  TAutoObjectFactory.Create(ComServer, TSysLog, Class_SysLog,
    ciMultiInstance, tmApartment);
end.

Зарегистрируйте компонент в каталоге COM+ и подпишите его к компоненту EventClass.

Далее следуйте инструкциям визарда.

Итак, у вас на компьютере установлены объекты EventClass и подписчик.

Пример реализации методов издателя

Создадим простенькое приложение и проверим существующею связку. Создайте бизнес-объект COM+ инициирующий в любом своем методе метод-событие ReportLog.

Пример реализации объекта приведен ниже:


unit BsObjectUnit;

interface

uses
  ComObj, ActiveX, BsObject_TLB, StdVcl, LogEvent_TLB;

type
  TBusinessObject = class(TAutoObject, IBusinessObject)
  protected
    { Protected declarations }
    function NewObject(param1: Integer): HResult; safecall;
end;

implementation

uses
  ComServ;

function TBusinessObject.NewObject(param1: Integer): HResult;
var
  LogEvent: ISysLogEvent;
begin
  LogEvent := CoSysLogEvent.Create;
  try
    LogEvent.ReportLog(lmtInformation, 'Nonamed', 'BsObjectUnit',
      'TBusinessObject.NewObject executed!')
  except
    LogEvent.ReportLog(lmtInformation, 'Nonamed', 'BsObjectUnit',
      'TBusinessObject.NewObject failed!')
  end;
end;

initialization
TAutoObjectFactory.Create(ComServer, TBusinessObject,
  Class_BusinessObject, ciMultiInstance, tmApartment);

end.

После вызова метода NewObject у объекта BusinessObject будет создано событие, которое создаст объект SysLog и запишет и отобразит информацию в диалоговом окне. Подписчиков у созданного объекта EventClass может быть неограниченное количество с самыми разнообразными функциями, от отображения диалогового окна до записи данных в отдельную БД.

Фильтры

Механизм фильтрации подписчиков использует строку условия фильтрации, являющуюся свойством подписки. Такая фильтрация выполняется для каждого метода и каждой подписки. Вы можете использовать строку, используя имена параметров из библиотеки типов. Можно использовать так же стандартные операции отношения, вложенные скобки и ключевые слова AND, OR, NOT. Строка может быть определена с помощью средств ComponentServices или средств административного API.

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay