Создание и уничтожение канала
Последнее, что нужно сделать перед началом передачи данных по каналу DDEML, - создать канал связи (conversation). Теперь мы к этому вполне готовы.
Кто является инициатором создания канала?
Канал связи между клиентом и сервером создается всегда по инициативе клиента. После регистрации в библиотеке DDEML клиент вызывает функцию DdeConnect, создающую канал связи:
HCONV WINAPI DdeConnect( DWORD idInst, // идентификатор приложения HSZ hszService, // идентификатор строки сервиса HSZ hszTopic, // идентификатор строки раздела CONVCONTEXT FAR* pCC); // адрес данных контекста
Через параметр idInst приложение должно передать идентификатор, полученный на этапе регистрации приложения в библиотеки DDEML функцией DdeInitialize.
Параметры hszService и hszTopic предназначены для передачи идентификаторов строк, содержащих, соответственно, имена сервиса и раздела. Эти идентификаторы были получены нами ранее при помощи функции DdeCreateStringHandle.
Последний параметр - указатель на структуру типа CONVCONTEXT. Эта структура используется для указания информации о национальном языке и кодовой странице, соответствующей передаваемым данным. В простейшем случае для данного параметра можно указать значение NULL, при этом будет использована кодовая страница CP_WINANSI (что приемлемо в подавляющем большинстве случаев).
В нашем приложении DDEMLCL для создания канала с сервером используется следующий фрагмент кода:
hConv = DdeConnect(idInst, hszService, hszTopic, (PCONVCONTEXT)NULL);
Идентификатор канала, полученный от функции DdeConnect, следует сохранить для обеспечения возможности получения данных от сервера.
Что же происходит, когда клиент создает канал, вызывая функцию DdeConnect?
Прежде всего, библиотека DDEML посылает транзакцию с кодом XTYP_CONNECT всем активным серверам, которые зарегистрировали сервис, указанный во втором параметре функции DdeConnect.
Для транзакции XTYP_CONNECT параметры функции обратного вызова принимают следующие значения:
Параметр | Значение |
hsz1 | Идентификатор строки, содержащей имя раздела |
hsz2 | Идентификатор строки, содержащей имя сервиса |
dwData1 | Адрес структуры CONVCONTEXT |
dwData2 | Если значение равно TRUE, данная копия приложения является одновременно и клиентом, и сервером. Если же значение равно FALSE, клиент и сервер являются разными приложениями или разными копиями приложения |
Обработчик транзакции XTYP_CONNECT, расположенный в функции обратного вызова сервера, должен проверить сервис и раздел, идентификаторы которых переданы через параметры функции. Если сервер поддерживает этот сервис и раздел, можно создавать канал. В таком случае функция обратного вызова должна вернуть значение TRUE. Иначе следует вернуть FALSE.
Приведенный ниже фрагмент кода, взятый из нашего приложения DDEMLSR, проверяет только сервис (так как в нашем приложении определен только один сервис и один раздел):
case XTYP_CONNECT: { if((HSZ)hsz2==(HSZ)hszService) return((HDDEDATA)TRUE); else return((HDDEDATA)FALSE); }
Заметим, что мы сравниваем не строки, содержащие имя сервиса, а идентификаторы, так как для одинаковых строк в данном случае будут созданы одинаковые идентификаторы.
В случае успешного создания канала сервер получает от системы DDEML транзакцию с кодом XTYP_CONNECT_CONFIRM. При обработке этой транзакции сервер может сохранить идентификатор созданного канала (который передается функции обратного вызова через параметр hConv) для дальнейшего использования.
Приведем назначение параметров функции обратного вызова для транзакции XTYP_CONNECT_CONFIRM:
Параметр | Значение |
hsz1 | Идентификатор строки, содержащей имя раздела |
hsz2 | Идентификатор строки, содержащей имя сервиса |
dwData2 | Если значение равно TRUE, данная копия приложения является одновременно и клиентом, и сервером. Если же значение равно FALSE, клиент и сервер являются разными приложениями или разными копиями приложения |
BOOL WINAPI DdeDisconnect(HCONV hConv);
В качестве единственного параметра этой функции передается идентификатор уничтожаемого канала.
В процессе удаления канала "партнер" приложения, выступившего инициатором удаления канала, получает транзакцию XTYP_DISCONNECT. Соответствующий обработчик может при необходимости выполнить действия по освобождению ресурсов, заказанных приложением для работы с данным каналом связи.
Приложение DDEMLSR обрабатывает транзакцию XTYP_DISCONNECT следующим образом:
case XTYP_DISCONNECT: { hConvApp = NULL; break; }
Все, что делает этот фрагмент кода - это запись нулевого значения в идентификатор не существующего больше канала связи.