Шаг 36.
Серверы и контроллеры автоматизации. Нотификационные сообщения во внепроцессных серверах

    На этом шаге мы рассмотрим общие принципы организации нотификационных сообщений.

    При анонсировании протокола автоматизации OLE в 1995 г. нотификациоиные сообщения (передача уведомлений от сервера к клиенту) не предусматривались. Например, если на сервере автоматизации менялись данные, он не мог сообщить об этом клиенту, хотя сам клиент мог как угодно часто опрашивать сервер, фиксируя факт изменения данных. В результате частый опрос сервера приводил к резкому возрастанию трафика в сети (если сервер сетевой) или к напрасной трате времени и ресурсов приложения-клиента. Многих разработчиков такая ситуация не устраивала, и это привело к разработке ряда оригинальных методик. Для СОМ-объектов (к которым относится и сервер автоматизации) уведомление клиента осуществляется посредством интерфейса IConnectionPoint. Компания Borland впервые реализовала его в Delphi 4.

    Если на странице ActiveX окна репозитария объектов выбрать значок Automation Object, то в окне мастера создания объектов автоматизации (рисунок 1) можно указать, что желательно создать сервер с поддержкой нотификационных сообщений. Для этого нужно установить флажок Generate Event support code.


Рис.1. Задание имени класса

    После того как с помощью мастера будет создан сервер автоматизации с поддержкой нотификационных сообщений, в библиотеке типов появятся интерфейс IDispatch и диспинтерфейс. К интерфейсу IDispatch следует добавить свойства и методы, которые будут вызываться из клиента автоматизации. А вот к диспинтерфейсу следует добавить события, о которых сервер будет уведомлять клиента. По сравнению с модулем реализации сервера автоматизации без поддержки нотификаций в модуле реализации библиотеки типов требуется сделать следующие изменения.

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

  1. При разработке клиентского приложения в нем необходимо реализовать диспинтерфейс, то есть создать класс с реализацией его методов. Идентификатор GUID и список методов этого диспинтерфейса берутся из библиотеки типов сервера. Для разработанного ранее примера это интерфейс ITestEvents.


    Рис.2. Редактор библиотеки типов созданного сервера

        В Delphi 4 для этого приходилось писать код вручную. В более поздних версиях Delphi появилась возможность автоматически создавать интерфейс в клиентском приложении путем установки флажка Generate Component Wrapper:


    Рис.3. Импорт библиотеки типов сервера

  2. При обращении клиента к СОМ-серверу и получении ссылки на фабрику классов клиент обращается к серверу за интерфейсом IConnectionPointContainer.
  3. После получения ссылки на интерфейс IConnectionPointContainer клиент вызывает его метод FindConnectionPoint. В качестве параметра этого метода используется GUID реализованного на клиенте диспинтерфейса, в нашем примере - ITestEvents.
  4. Метод IConnectionPointContaner.FindConnectionPoint реализуется на сервере таким образом, что он просматривает GUID всех нотификационных диспинтерфейсов, определенных на сервере (а их может быть несколько). Если запрашиваемый идентификатор GUID будет найден, то клиенту передается ссылка на интерфейс IConnectionPoint, который уже работает с конкретным нотификационным диспинтерфейсом.
  5. При получении ссылки на интерфейс IConnectionPoint клиент вызывает его метод Advise. В качестве параметра этого метода используется ссылка на экземпляр интерфейса, реализованного на клиенте.
  6. Сервер при вызове метода IConnectionPoint.Advise вызывает EventSinkChanged. В этом методе запоминается ссылка на клиентский интерфейс в переменной FEvents. Возвращаемый параметр метода IConnectionPoint.Advise - идентификатор.
  7. Клиент получает и запоминает идентификатор с сервера. Теперь клиент готов принимать нотификации.
  8. Когда клиенту более не нужны нотификации (например, перед завершением работы), клиент вновь получает ссылку на интерфейс IConnectionPoint, как это было описано в пп. 2-4, и вызывает уже другой метод IConnectionPoint.UnAdvise. В качестве параметра этого метода используется идентификатор, полученный в п. 7.
  9. Сервер вновь вызывает метод EventSinkChanged с параметром nil, который запоминается в переменной FEvents. С этого момента нотификации клиенту не передаются.

    В Delphi 4 всю описанную последовательность вызовов методов (за исключением п. 6) программисту необходимо было кодировать вручную. В последующих версиях Delphi все эти методы вызываются автоматически.

    На следующем шаге мы рассмотрим реализацию описанного алгоритма на практике.




Предыдущий шаг Содержание Следующий шаг