Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
экзамен СП.docx
Скачиваний:
13
Добавлен:
22.04.2019
Размер:
515.86 Кб
Скачать

17. Событийное управление в Win32. Сообщения и очереди сообщений Windows (Windows messages): назначение, структура, отсылка, доставка, обработка.

Сообщения и очереди сообщений.

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

Данный подход в действительность используется шире, чем только для обслуживания ввода-вывода, но и для организации взаимодействия программ и подпрограмм – концепция т.н. событийного управления. Она включает не только сам порядок работы модуля (активность – ожидание – активизация), но и унифицированные средства его обеспечения – в случае Win 32 это механизм передачи и обработки сообщений.

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

Вызов функции окна называют передачей сообщения этому окну. В качестве обязательного параметра в функцию окна передается именованная константа, называемая кодом или идентификатором сообщения (message identifier)

Другие параметры определяют дополнительные данные, связанные с данным сообщением. Например, при нажатии левой кнопки мыши в тот момент, когда указатель мыши находится над клиентской областью окна, окну передается сообщение WM_LBUTTONDOWN. При этом в качестве параметров передаются координаты указателя и состояние других кнопок мыши и клавиш SHIFT и CTRL.

Структура MSG.

Получение сообщений

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

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

BOOL GetMessage(LPMSG lpMessage,HWND hWindow,UINT nMsgMin,UINT nMsgMax) – выборка сообщения из очереди. Параметр hWindow задает окно, чьи сообщения будут приняты (значение NULL соответствует всем окнам данного приложения), nMsgMin и nMsgMax – нижнюю и верхнюю границы диапазона принимаемых сообщений (нулевые границы соответствуют всем имеющимся сообщениям без ограничений). Функция заполняет переданную структуру lpMessge и возвращает код результата: нулевое значение (FALSE) если принято сообщение WM_QUIT (завершение приложения) или ненулевое (TRUE) во всех остальных случаях. При отсутствии в очереди подходящих сообщений функция ожидает их появления, вызвавший ее поток на это время блокируется.

BOOL PeekMessage(LPMSG lpMessage,HWND hWindow,UINT nMsgMin,UINT nMsgMax,WINT wRmFlag) – проверка сообщения в очереди или выборка без ожидания. Отличается от предыдущей тем, что при отсутствии в очереди подходящих сообщений немедленно возвращает нулевое значение, в остальных случаях код возврата ненулевой. Дополнительный параметр wRmFlag указывает на способ обращения с обнаруженным сообщением: PM_REMOVE – сообщение удаляется из очереди, PM_NOREMOVE – сообщение не удаляется.

BOOL WaitMessage(void) – ожидание появления сообщения в очереди. Вызвавший поток переводится в состояние ожидания до появления в его очереди хотя бы одного сообщения любого типа.

Типичный цикл обработки сообщений состоит из функций: GetMessage(), TranslateMessage(), и DispatchMessage().

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

TranslateMessage(&msg);

DispatchMessage(&msg);

}

(Функции TranslateMessage(), DispatchMessage() см. ниже)

Распространение и обработка сообщений

При нажатии клавиш Windows посылает активному окну сообщения WM_KEYDOWN и WM_KEYUP. Эти сообщения содержат некоторые виртуальные коды клавиш, а не символы. Для анализа нажатий и порождения сообщений WM_CHAR, которые содержат символьные коды клавиш, используется функция TranslateMessage().

Для того, чтобы направить сообщение на обработку соответствующему окну, используется функция DispatchMessage().

(к чему бы это приспособить?) Приложение может завершить себя посылкой сообщения WM_QUIT. Для этого предназначена функция PostQuitMessage(). Обычно она вызывается в ответ на получение главным окном приложения сообщения WM_DESTROY. Важно учитывать, что это сообщение не требует от приложения "разрушить" окно, а извещает его, что процесс разрушения уже идет (хотя и не завершился), и скоро окно перестанет существовать, и, соответственно, поступление новых сообщений прекратится.

Посылка сообщений

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

LRESULT SendMessage(HWND hWindow,UINT nMsg,WPARAM WParam,LPARAM LParam) – непосредственная передача сообщения обработчику. Параметр hWindow идентифицирует окно-получатель сообщения, а остальные параметры определяют соответствующие параметры сообщения (см. выше). Результатом функции является значение кода возврата оконной процедуры получателя, поэтому выполнение потока, вызвавшего SendMessage, приостанавливается до окончания обработки этого сообщения.

BOOL SendMessage(HWND hWindow, UINT nMsg, WPARAM wParam, LPARAM lParam) – передача сообщений посредством очереди (постановка в очередь). Список его параметров аналогичен, но возврат из функции всегда немедленный, и результат отражает успешность вызова: нулевое значение является признаком ошибки.

BOOL SendNotifyMessage(HWND hWindow, UINT nMsg, WPARAM wPa­ram,LPARAM lParam) – совмещает свойства предыдущих: передача сообщения непосредственно в обработчик, но без ожидания его выполнения и без анализа результата обработки. Возвращаемое значение характеризует результативность вызова: ноль (FALSE) соответствует ошибке.

Сопоставляя функции, можно отметить следующее:

1) SendMessage() обеспечивает двусторонний обмен информацией, т.к. подразумевает содержательный код возврата, что приближает ее по функциональности к вызову подпрограммы; в то же время, в случае неготовности или неспособности получателя обработать такое сообщение программа-источник будет заблокирована;

2) PostMessage() позволяет избежать блокировки, более того, сообщение может быть поставлено в очередь даже не существующего приложения. Однако факт обработки или игнорирования сообщения целиком зависит от приложения-получателя;

3) SendNotifyMessage() не имеет обратной связи, не вызывает блокировок и гарантирует быстрое получение сообщения адресатом.

4) PostThreadMessage() также работает через очередь сообщений, но получателем является не окно, для которого система будет подбирать соответствующий ему поток, а непосредственно поток (по ID потока). Т.о., просто удаляется одно звено в цепи поиска получателя, и появляется возможность адресовать сообщения потокам, не связанным с окнами.

Как следствие, по соображениям надежности предпочтительнее передача сообщений через очередь, если только не требуется обратная связь. Стандартно так передаются сообщения информационного типа: ввода-вывода, таймер, перерисовка и т.п. Некоторые сообщения следует обязательно передавать через очередь, например, WM_QUIT, для которого предусмотрена специальная функция PostQuitMessage().

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

В всех случаях в качестве окна-получателя допустимо указывать константу HWND_BROADCAST, что соответствует "широковещательной" посылке его всем существующим в системе окнам верхнего уровня, включая невидимые. Кроме того, в PostMessage() можно использовать значение этого параметра NULL – сообщение передается в очередь того же потока, который его посылает; аналогично можно использовать и PostThreadMessage().

В Приложении приведен пример программы, демонстрирующей создание подчиненных оконных элементов (кнопок) средствами API, их использование и управление.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]