Смекни!
smekni.com

Обмен данными в Windows (стр. 5 из 8)

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

// // wait for time out // static BOOL TimeOut( HWND hWnd, UINT wMsg, UINT uTimeOut ) { DWORD dwTime; MSG msg;

// FALSE design normal termination // TRUE design time-out or negative WM_DDE_ACK dwTime= GetCurrentTime(); while ( dwTime + uTimeOut > GetCurrentTime() ) { if ( PeekMessage( &msg, hWnd, NULL, NULL, PM_REMOVE ) ) { // обработатьполученноесообщение TranslateMessage( &msg ); DispatchMessage( &msg ); if ( msg.message == WM_DDE_ACK ) { // check for .fAck return LOWORD( msg.lParam ) & 0x8000 ? FALSE : TRUE; } else if ( msg.message == wMsg ) return FALSE; } }

return TRUE; }

Обычно процедура, ожидающая нужное сообщение, выглядит несколько иначе. Это связано с желательным отображением курсора ожидания (в виде песочных часов), а также с обработкой сообщений, извлеченных из очереди. Во многих случаях нормальная обработка сообщений не сводится только к функциям TranslateMessage и DispatchMessage, но также включает поддержку акселераторов, немодальных диалогов и пр. Помимо этого следует учесть, что в случае платформы Windows 3.x размер очереди сообщений приложения сравнительно невелик — так что при извлечении сообщений, направленных только конкретному окну, очередь может легко переполниться.

Еще одно замечание касается времени ожидания ответа от сервера. Этот промежуток не надо назначать очень большим, но в то же время он должен быть достаточным, что бы даже на медленных машинах уверенно получать ответ от сервера. При избыточно большом времени ожидания ответа может возникать впечатление “зависания” приложения, пока оно ждет ответа. Обычно человек ожидает от компьютера почти мгновенной реакции или, в худшем случае, явно видимой работы. Если программа останавливается на срок более 10–15 секунд, то уже возникает беспокойство о ее работе.

Практически приемлемым является интервал порядка 5–30 секунд, так как на средней машине ответ может задерживаться до 5–10 секунд при нормальной работе и, соответственно, на медленных машинах интервал следует увеличить примерно до тридцати секунд. (Различие между быстрыми и медленными машинами весьма относительно — с ростом мощности компьютеров растет нагрузка на них, поэтому время выполнения более–менее значительных операций снижается сравнительно медленно). Возможным решением является двухэтапное ожидание — первый этап до 3–6 секунд проходит как обычно, а по истечении этого интервала отображается окно диалога с кнопкой “Cancel”, после чего ожидание продолжается либо до получения ответа, либо до отмены ожидания пользователем. Это позволяет пользователю оценить занятость системы и, при необходимости, продолжить ожидание в разумных пределах.

Задача определения времени ожидания ответа от сервера является достаточно важной из–за необходимости освобождать занятые ресурсы. Фактически, при обмене сообщениями возникает следующая ситуация: при посылке каких либо разделяемых объектов от одного приложения к другому (это могут быть атомы или глобальные блоки данных) необходимо эти объекты удалять после их использования. Однако тут надо учесть следующие нюансы:

· если функция PostMessage не может послать сообщение, объекты можно удалять сразу, так как второе приложение их не получит.

· если сообщение послано, то момент уничтожения объектов выбирается в соответствии с описанием сообщения в документации. Так, например, атомы обычно удаляются по следующей схеме

- при получении посланного запроса проверяется необходимость ответа, если ответ нужен, то атом передается вместе с ответом и уничтожается приложением, пославшим запрос

- если ответ нужен, но его послать не удается, то атом уничтожается получившим запрос приложением

- если ответ не нужен, то атом опять–же уничтожается получившим запрос приложением

· посланное сообщение может “не дойти” до адресата (например, если окно–получатель будет закрыто уже после того, как к нему в очередь попадет это сообщение, но до его обработки). При этом ответа не будет, а приложение–получатель освободить ресурсы не сможет.

· посланное сообщение может быть успешно принято, а при его обработке, но уже после освобождения полученных ресурсов, получатель не сможет отправить обратно необходимого подтверждения.

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

“Горячая” связь — hot link

Протокол при горячей связи. После инициации обмена клиент посылает запрос WM_DDE_ADVISE, указывая желаемые данные. Сервер отвечает о возможности горячей связи, и, обычно, сразу же посылает первые данные, для инициации клиента. Таким образом осуществялется как–бы “подписка” на получение необходимых данных при их изменении. Этот вид связи удобен, если Вам необходимо взаимодействовать с какой–либо базой данных, содержимое которой может динамически обновляться, как например база данных “товары на складе” для больших магазинов — доступ к этой базе одновременно могут иметь разные отделы магазина и список товаров, имеющихся на сладе, постоянно изменяется. Использование горячей связи в этом случае позволит создать локальные списки на компьютерах разных отделов и автоматически обновлять их, как только осуществляется изменение общей базы данных.

WM_DDE_ADVISE hWnd aItem & hOptions (Packed Win32)

Младший компонент параметра lParam содержит хендл глобального разделяемого блока, содержащего небольшую структуру DDEADVISE, а старший компонент — атом, описывающий данные на которые осуществляется подписка. Структура DDEADVISE определяет тип связи — горячая или холодная, а также необходимость требовать подтверждения о доставке данных от клиента. В случае платформы Win32 параметр lParam используется для передачи “упакованного” значения. Сервер, получивший это сообщение обязан ответить на него посылкой подтверждения WM_DDE_ACK, положительного или отрицательного. Освобождение ресурсов: Клиент, пославший запрос, должен дождаться ответа от сервера. Если ответ положительный, то блок данных должен быть удален сервером, а если отрицательный, то клиент должен сам его удалить.

Структура DDEADVISE содержит следующие данные:

typedef struct { WORD reserved:14, fDeferUpd:1, // 1-”теплая” связь, 0-”горячая” fAckReq:1; // 1-необходимо требовать подтверждение, 0-не надо short cfFormat; // желаемый формат данных } DDEADVISE;

При задании бита fDeferUpd равным 1 осуществляется так называемая теплая связь, при которой сервер только информирует о наличии у него измененных данных, но не посылает их клиенту непосредственно. В случае горячей связи этот бит должет быть равен 0. Бит fAckReq, равный 1, указывает на необходимость требовать от клиента подтверждения о получении данных. Позже, когда сервер начнет посылать клиенту сообщения WM_DDE_DATA он установит в структуре DDEDATA бит fAckReq соответствующим тому, который Вы указали в структуре DDEACK и, соответственно, клиент должен будет подтверждать получение им данных от сервера (надо учесть, что бит fAckReq влияет на стратегию освобождения посылаемых данных — подробнее см. описание сообщения WM_DDE_DATA).

Поле cfFormat указывает на формат данных, которые клиент ожидает от сервера. Вы можете для одного вида данных в пределах одного DDE–разговора подписаться на получение данных разного типа одновременно, посылая WM_DDE_ADVISE столько раз, сколько форматов данных Вы хотите получать. Однако такая возможность разрешена только для горячей связи. Согласно документации подписка на одни и те–же данные в разных форматах для теплой связи запрещена.

Сервер, при получении сообщения WM_DDE_ADVISE, проверяет возможность осуществить подписку на эти данные, создает необходимые ему структуры данных и отвечает клиенту сообщением WM_DDE_ACK — положительным или отрицательным. Это сообщение в данном случае используется так–же, как и при ответе на WM_DDE_DATA.

Если подписка осуществлена успешно, то далее сервер начинает извещать клиента об обновлении данных, осуществляя каждый раз пересылку этих данных клиенту с помощью уже рассмотренного сообщения WM_DDE_DATA. Единственное отличие от получения данных в ответ на WM_DDE_REQUEST заключается в том, что бит fResponse структуры DDEDATA равен 0, тогда как при отправке данных по запросу он устанавливается в 1. Это позволяет определить причину получения данных при обработке сообщения.

Заканчивается такой обмен посылкой WM_DDE_UNADVISE серверу. В этом сообщении указывается, от подписки на какие данные клиент отказывается (так как теоретически один клиент может подписаться сразу на несколько видов данных).

WM_DDE_UNADVISE hWnd aItem & cfFormat

Младшее слово параметра lParam описывает формат данных, а старшее слово — атом, описывающий данные на которые осуществляется подписка. В случае платформы Win32 параметр lParam используется также, как и в случае Windows 3.x. Если параметр cfFormat равен 0, то отменяется подписка на указанные данные для всех тех форматов, для которых была осуществлена подписка. Если параметр aItem равен NULL, то отменяется подписка на все виды данных в пределах данного DDE–разговора. Сервер, обработав это сообщение, должен послать в ответ подтверждение WM_DDE_ACK, положительное или отрицательное; при этом если одна операция отменяет подписку на данные в разных форматах, то посылается только одно подтверждение.