Операционная система Microsoft Windows 3.1 для программиста. Дополнительные главы

         

Регистрация сервиса


Следующий этап в инициализации сервера DDEML заключается в регистрации предоставляемого им сервиса.

Библиотека DDEML использует трехступенчатую схему адресации данных, передаваемых по каналу связи - сервис (service), раздел (topic) и элемент данных (data item). Приложение задает элементы адреса в виде текстовых строк размером не более 255 байт. Это ограничение возникло в результате использования для реализации DDEML атомов, которые представляют собой идентификаторы текстовых строк, хранящихся в специальной системной таблице (для Windows версии 3.1). Размер таких строк не должен превышать 255 байт.

Сервер DDEML может предоставлять сервис одного или нескольких видов. Как правило, один сервер предоставляет только один сервис, причем текстовая строка, идентифицирующая сервис, часто совпадает с именем приложения. Но можно выбрать любую другую строку. Например, наше приложение DDEMLSR предоставляет сервис "BMPService". Как можно догадаться из названия, этот сервис связан с bmp-файлами (в действительности мы привели сильно упрощенную версию сервера bmp-файлов, в которой для сокращения объема листингов изъяты функции обслуживания bmp-файлов).

Второй элемент адреса - раздел. В рамках одного сервиса можно определить несколько разделов. Когда клиент DDEML создает канал с сервером, он указывает сервис и раздел. Раздел объединяет группу элементов данных или выполняемых функций. В приложении DDEMLSR определен один раздел "BMPFile".

Канал DDEML служит для передачи блоков данных. В рамках одного раздела сервер может обмениваться с клиентом разными блоками данных, каждый из которых идентифицируется при передаче именем элемента данных. В процессе создания канала связи не требуется указывать элементы данных.

Для иллюстрации сказанного выше предположим, что мы создаем сервер BMPSERV.EXE, предназначенный для отображения битовых изображений DIB, причем путь к соответствующему bmp-файлу и управляющая информация должны передаваться серверу через канал связи DDE.

При регистрации сервер BMPSERV.EXE регистрирует один сервис "BMPServer" и два раздела: "BMPFile" и "Control" (рис. 3.4).






Рис. 3.4. Сервис, разделы и элементы данных для сервера BMPSERV

В разделе "BMPFile" определены элементы данных "Filename" (имя отображаемого bmp-файла) и "Title" (заголовок изображения или подпись под изображением). В разделе "Control" определен один элемент данных "Mode", определяющий режим отображения (размеры и расположение окна, органы управления для работы с изображением и т. п.).

Клиент может создавать два канала с сервером. Первый канал можно обозначить как BMPServer/BMPFile, второй - BMPServer/Control. Через канал BMPServer/BMPFile передается путь к отображаемому файлу и заголовок изображения, а через канал BMPServer/Control клиент может управлять режимом отображения.



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

Регистрация сервиса выполняется сервером DDEML обычно сразу после вызова функции DdeInitialize и выполняется в два этапа.

На первом этапе текстовая строка имени сервиса сохраняется в специальной системной таблице (таблице атомов), для чего вызывается функция DdeCreateStringHandle:

HSZ WINAPI DdeCreateStringHandle( DWORD idInst, // идентификатор приложения LPCSTR psz, // адрес текстовой строки int iCodePage); // кодовая страница

Через параметр idInst приложение должно передать идентификатор, полученный на этапе регистрации приложения в библиотеке DDEML функцией DdeInitialize.

Параметр psz представляет собой указатель на текстовую строку, закрытую двоичным нулем. Размер этой строки не должен превышать 255 байт.

В качестве значения для параметра iCodePage можно указать CP_WINANSI (эта константа равна нулю). Можно также использовать значение, полученное от функции GetKBCodePage. Функция GetKBCodePage не имеет параметров и возвращает номер текущей кодовой страницы.

Идентификатор текстовой строки, возвращенный функцией DdeCreateStringHandle и соответствующий регистрируемому сервису, следует передать функции DdeNameService:



HDDEDATA WINAPI DdeNameService( DWORD idInst, // идентификатор приложения HSZ hsz1, // идентификатор строки имени сервиса HSZ hsz2, // зарезервировано UINT afCmd); // флаги

Через параметр idInst приложение должно передать идентификатор, полученный на этапе регистрации приложения в библиотеке DDEML функцией DdeInitialize.

Параметр hsz1 предназначен для передачи имени сервиса через идентификатор текстовой строки, возвращенной функцией DdeCreateStringHandle.

Параметр hsz2 зарезервирован, для него следует использовать нулевое значение.

При регистрации сервиса через параметр afCmd следует передать значение DNS_REGISTER (регистрация сервиса). Сервер DDEML в процессе своей работы может динамически регистрировать и отменять виды предоставляемого сервиса. Для отмены сервиса через параметр afCmd передается значение DNS_UNREGISTER.

Перед завершением работы сервер DDEML должен отменить весь зарегистрированный им ранее сервис, вызвав функцию DdeInitialize с параметром afCmd, имеющим значение DNS_UNREGISTER.

Если регистрация сервиса выполнена успешно, функция DdeNameService возвращает ненулевое значение, а при ошибке - нулевое.

Приведем фрагмент кода, выполняющего регистрацию сервиса "BMPServer":

hszService = DdeCreateStringHandle(idInst, "BMPServer", CP_WINANSI); DdeNameService(idInst, hszService, (HSZ)NULL, DNS_REGISTER);

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

hszTopic = DdeCreateStringHandle(idInst, szTopic, CP_WINANSI); hszItem = DdeCreateStringHandle(idInst, szItem, CP_WINANSI);

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

Зная идентификатор строки, приложение может получить строку, вызвав функцию DdeQueryString:

DWORD WINAPI DdeQueryString( DWORD idInst, // идентификатор приложения HSZ hsz, // идентификатор строки LPSTR psz, // адрес буфера для записи строки DWORD cchMax, // размер буфера int iCodePage); // кодовая страница

Назначение параметров понятно из комментариев в прототипе функции.

Если идентификатор созданной текстовой строки используется в функции обратного вызова (которую мы рассмотрим чуть позже), за освобождение ресурсов, связанных с текстовой строкой, отвечает система DDEML. В противном случае приложение должно самостоятельно уничтожать созданные им идентификаторы, вызывая функцию DdeFreeStringHandle:

BOOL WINAPI DdeFreeStringHandle( DWORD idInst, // идентификатор приложения HSZ hsz); // идентификатор уничтожаемой строки

В случае успеха функция DdeFreeStringHandle возвращает ненулевое значение, при ошибке - нулевое.


Содержание раздела