
- •Глава 17 Динамический обмен данными
- •Основные концепции
- •Приложение, раздел и элемент
- •Типы диалогов
- •Символьные строки и атомы
- •Программа сервер dde
- •Программа ddepop1
- •Сообщение wm_dde_initiate
- •Оконная процедура ServerProc
- •Сообщение wm_dde_request
- •Функция PostDataMessage программы ddepop1
- •Сообщение wm_dde_advise
- •Обновление элементов данных
- •Сообщение wm_dde_unadvise
- •Сообщение wm_dde_terminate
- •Программа-клиент dde
- •Инициирование диалога dde
- •Сообщение wm_dde_data
- •Сообщение wm_dde_terminate
- •Управляющая библиотека dde
- •Концептуальные различия
- •Реализация dde с помощью ddeml
Оконная процедура ServerProc
С отправкой сообщения WM_DDE_ACK в ответ на сообщение WM_DDE_INITIATE начинается диалог DDE. Как уже говорилось, когда WndProc посылает обратно клиенту сообщение WM_DDE_ACK, параметром wParam этого сообщения становится описатель дочернего окна, которое она создает для диалога. Это означает, что все последующие сообщения DDE проходят между клиентом и этим дочерним окном, оконной процедурой которого является ServerProc.
ServerProc при обработке сообщения WM_CREATE выделяет память, необходимую для хранения NUM_STATES структур типа POPADVISE. (Об их использовании скоро будет рассказано.) Описатель этого блока памяти с помощью функции SetWindowLong сохраняется во втором зарезервированном двойном слове. Этот блок памяти освобождается, когда ServerProc получает сообщение WM_DESTROY.
Сообщение wm_dde_request
Клиент посылает серверу синхронное сообщение WM_DDE_REQUEST, когда ему нужны данные, которые соответствуют конкретному элементу. Этот тип транзакции известен как холодная связь. Сервер отвечает, посылая клиенту синхронное сообщение WM_DDE_DATA с данными или сообщение WM_DDE_ACK, если он не может удовлетворить запрос. Рассмотрим, как ServerProc обрабатывает сообщение WM_DDE_REQUEST.
Как обычно у сообщений DDE, параметр wParam сообщения WM_DDE_REQUEST является описателем окна, пославшим синхронное сообщение, в данном случае клиента. Младшее слово параметра lParam представляет из себя запрашиваемый формат данных. Старшее слово параметра lParam представляет из себя атом, идентифицирующий запрашиваемый элемент данных.
Форматы данных DDE аналогичны форматам папки обмена, поэтому младшее слово параметра lParam чаще всего будет одним из идентификаторов, начинающихся с префикса CF. Клиент может послать серверу несколько сообщений WM_DDE_REQUEST для одного и того же элемента, но с разными форматами. Сервер должен ответить, используя сообщение WM_DDE_DATA только для тех форматов, которые он поддерживает. Поскольку самым используемым форматом DDE является CF_TEXT, то только этот формат поддерживает программа DDEPOP1.
Таким образом, при обработке сообщения WM_DDE_REQUEST ServerProc сначала проверяет, является ли запрашиваемый формат — форматом CF_TEXT. Затем ServerProc для получения символьной строки, соответствующей атому, переданному в старшем слове параметра lParam, вызывает функцию GlobalGetAtomName. Если клиент знает, что это должна быть двухсимвольная строка, идентифицирующая штат. Цикл for просматривает имеющиеся штаты с целью найти совпадение между этой строкой и полем szState структуры pop. Если это удается, то ServerProc, используя вызов функции GlobalDeleteAtom, удаляет атом, а затем вызывает функцию PostDataMessage (функция, находящаяся в конце программы DDEPOP1, которая посылает синхронное сообщение WM_DDE_DATA. Эту функцию мы еще рассмотрим). Затем ServerProc завершается.
Если запрашиваемый формат не является форматом CF_TEXT, или, если не удалось найти совпадения между атомом элемента и одним из названий штатов, то ServerProc отправляет негативное синхронное сообщение WM_DDE_ACK, означающее, что данные не были обнаружены. Это делается путем задания в поле fAck структуры DDEACK (определенной в файле DDE.H) значения FALSE. Структура DDEACK преобразуется в слово, которое становится младшим словом параметра lParam. Старшим словом параметра lParam является атом запрашиваемого элемента. Вызывая функцию PostMessage, клиенту посылается синхронное сообщение WM_DDE_ACK.
Обратите внимание, как здесь обрабатывается атом. В документации о сообщении WM_DDE_REQUEST говорится: "Отвечая на сообщение WM_DDE_DATA или на сообщение WM_DDE_REQUEST, приложение-сервер может либо повторно использовать атом aItem, либо оно может удалить атом и создать новый." Это означает то, что состояние глобальной таблицы атомов не должно изменяться сервером, т. е. счетчик ссылок для атома aItem не должен ни увеличиваться, ни уменьшаться.
Существует три возможных варианта:
Если требуемым форматом является CF_TEXT, и атом соответствует одному из названий штатов, то ServerProc перед тем, как вызвать функцию PostDataMessage из файла DDEPOP1.С, вызывает функцию GlobalDeleteAtom. Функция PostDataMessage (как мы скоро увидим) при отправке клиенту синхронного сообщения WM_DDE_DATA воссоздает удаленный атом.
Если требуемый формат отличен от CF_TEXT, или, если атом не совпадает ни одним из названий штатов, то ServerProc для отправки клиенту негативного сообщения WM_DDE_ACK вызывает функцию PostMessage. В этом сообщении атом просто используется повторно.
Однако, при неудачном вызове функции PostMessage (что возможно, если клиент неожиданно завершится) ServerProc удаляет атом, поскольку клиент этого сделать не может.
Мы еще не до конца разобрались с сообщением WM_DDE_REQUEST, поскольку еще не исследовали, как программа DDEPOP1, используя вызов функции PostDataMessage, посылает ответное сообщение WM_DDE_DATA. Об этом в следующем разделе.