На этом шаге мы рассмотрим общие принципы организации нотификационных сообщений.
При анонсировании протокола автоматизации OLE в 1995 г. нотификациоиные сообщения (передача уведомлений от сервера к клиенту)
не предусматривались. Например, если на сервере автоматизации менялись данные, он не мог сообщить об этом клиенту,
хотя сам клиент мог как угодно часто опрашивать сервер, фиксируя факт изменения данных. В результате частый опрос
сервера приводил к резкому возрастанию трафика в сети (если сервер сетевой) или к напрасной трате времени и ресурсов
приложения-клиента. Многих разработчиков такая ситуация не устраивала, и это привело к разработке ряда оригинальных
методик. Для СОМ-объектов (к которым относится и сервер автоматизации) уведомление клиента осуществляется
посредством интерфейса IConnectionPoint. Компания Borland впервые реализовала его в Delphi 4.
Если на странице ActiveX окна репозитария объектов выбрать значок Automation Object, то в окне
мастера создания объектов автоматизации (рисунок 1) можно указать, что желательно создать сервер с поддержкой
нотификационных сообщений. Для этого нужно установить флажок Generate Event support code.
Рис.1. Задание имени класса
После того как с помощью мастера будет создан сервер автоматизации с поддержкой нотификационных сообщений, в
библиотеке типов появятся интерфейс IDispatch и диспинтерфейс. К интерфейсу IDispatch следует
добавить свойства и методы, которые будут вызываться из клиента автоматизации. А вот к диспинтерфейсу следует
добавить события, о которых сервер будет уведомлять клиента. По сравнению с модулем реализации сервера
автоматизации без поддержки нотификаций в модуле реализации библиотеки типов требуется сделать следующие
изменения.
- Класс TAutoObject должен экспонировать интерфейс IConnectionPointContainer.
- Добавляется переменная FEvents - указатель на интерфейс, передающий нотификационные сообщения
клиенту. Этот интерфейс не создается в сервере автоматизации: он создается в клиенте автоматизации и ссылка на него
передается серверу. - Добавляется объект FConnectionPoint, в котором реализован интерфейс IConnectionPointContainer.
Он создается при инициализации сервера автоматизации. - Добавляется метод EventSinkChanged. Этот метод будет вызываться всякий раз, когда от клиента
будет передаваться ссылка на интерфейс приема нотификациониых сообщений. В частности, при выгрузке клиента из
памяти будет передаваться указатель nil. - При инициализации сервера создается интерфейс IConnectionPoint, который используется для связи
с клиентом.
Теперь следует рассмотреть последовательность вызовов методов, необходимых для поддержки нотификаций СОМ.
с реализацией его методов. Идентификатор GUID и список методов этого диспинтерфейса берутся из
библиотеки типов сервера. Для разработанного ранее примера это интерфейс ITestEvents.
Рис.2. Редактор библиотеки типов созданного сервера
В Delphi 4 для этого приходилось писать код вручную. В более поздних версиях Delphi появилась возможность
автоматически создавать интерфейс в клиентском приложении путем установки флажка Generate Component Wrapper:
Рис.3. Импорт библиотеки типов сервера
серверу за интерфейсом IConnectionPointContainer.
FindConnectionPoint. В качестве параметра этого метода используется GUID реализованного на
клиенте диспинтерфейса, в нашем примере - ITestEvents.
просматривает GUID всех нотификационных диспинтерфейсов, определенных на сервере (а их может
быть несколько). Если запрашиваемый идентификатор GUID будет найден, то клиенту передается ссылка
на интерфейс IConnectionPoint, который уже работает с конкретным нотификационным диспинтерфейсом.
В качестве параметра этого метода используется ссылка на экземпляр интерфейса, реализованного на клиенте.
В этом методе запоминается ссылка на клиентский интерфейс в переменной FEvents. Возвращаемый параметр
метода IConnectionPoint.Advise - идентификатор.
ссылку на интерфейс IConnectionPoint, как это было описано в пп. 2-4, и вызывает уже другой метод
IConnectionPoint.UnAdvise. В качестве параметра этого метода используется идентификатор, полученный в п. 7.
переменной FEvents. С этого момента нотификации клиенту не передаются.
В Delphi 4 всю описанную последовательность вызовов методов (за исключением п. 6) программисту
необходимо было кодировать вручную. В последующих версиях Delphi все эти методы вызываются автоматически.
На следующем шаге мы рассмотрим реализацию описанного алгоритма на практике.