Простой цикл обработки сообщений состоит из одной функции, которая обращается к каждой из этих трех функций: GetMessage, TranslateMessage и DispatchMessage.
Обратите внимание! на то, что если случается ошибка, функция GetMessage возвращает значение - (минус)1 - то есть здесь необходима специальная проверка. |
Демонстрационный пример
MSG msg; BOOL bRet; while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) { if (bRet == -1) { // обработка ошибки и возможный выход из программы } else { TranslateMessage(&msg); DispatchMessage(&msg); } } |
Функция GetMessage извлекает сообщение из очереди и копирует его в структуре типа MSG. Она возвращает значение не нуль, если не сталкивается с сообщением WM_QUIT , при наличии которого она возвращает значение ЛОЖЬ (FALSE) и заканчивает цикл обработки. В однопоточной прикладной программе, завершение цикла обработки сообщений является часто первым шагом в закрытии приложения. Прикладная программа может закончить свой собственный цикл, используя функцию PostQuitMessage, обычно в ответ на сообщение WM_DESTROY в оконной процедуре главного окна приложения.
Если Вы определяете дескриптор окна, как второй параметр GetMessage, из очереди извлекаются только сообщения для заданного окна. Функция GetMessage может также фильтровать сообщения в очереди, извлекая только те сообщения, которые попадают в пределы заданного диапазона значений. Для получения дополнительной информации о фильтрации сообщений, см. статью Фильтрация сообщений.
Цикл обработки сообщений потока должен включать в себя функцию TranslateMessage, если поток должен принять ввод символьной информации от клавиатуры. Система генерирует сообщения виртуальных клавиш (WM_KEYDOWN и WM_KEYUP) каждый раз, когда пользователь нажимает клавишу. Сообщение виртуальной клавиши содержит код виртуальной клавиши, который идентифицирует, какая клавиша была нажата, а не ее символьное значение. Чтобы извлечь это значение, цикл обработки сообщений должен содержать функцию TranslateMessage, которая переводит сообщение виртуальной клавиши в символьное сообщение (WM_CHAR ) и помещает его обратно в очередь сообщений прикладной программы. Символьное сообщение затем может быть забрано после последующего повтора цикла сообщений и отправлено целевой оконной процедуре.
Функция DispatchMessage посылает сообщение оконной процедуре, связанной с дескриптором окна, заданным в структуре MSG. Если дескриптор окна имеет флажок - HWND_TOPMOST, DispatchMessage посылает сообщение оконным процедурам всех окон верхнего уровня в системе. Если дескриптор окна - ПУСТО (NULL), DispatchMessage с сообщением не делает ничего.
Главный поток прикладной программы запускает свой цикл обработки сообщений после инициализации приложения и создания по крайней мере одного окна. После этого, запущенный цикл обработки сообщений продолжает извлекать сообщения из очереди сообщений потока и распределять их по соответствующим окнам. Цикл обработки сообщений заканчивается тогда, когда функция GetMessage забирает из очереди сообщение WM_QUIT.
Только один цикл обработки сообщений необходим для очереди сообщений, даже в том случае, если прикладная программа содержит много окон. Функция DispatchMessage всегда распределяет сообщение надлежащему окну; это получается так потому, что каждое сообщение в очереди - это структура MSG, которая содержит дескриптор окна, которому принадлежит сообщение.
Вы можете изменять цикл обработки сообщений различными способами. Например, Вы можете извлекать сообщения из очереди без отправки их окну. Это практикуется для прикладных программ, которые посылают сообщения, не для заданного окна. Вы можете также заставить функцию GetMessage искать специфические сообщения, оставляя другие сообщения в очереди. Это является полезным, если Вы должны временно обойти обычный FIFO порядок очереди сообщений.
Прикладная программа, которая использует клавиши - ускорители, должна получить возможность, чтобы переводить сообщения клавиатуры в командные сообщения. Чтобы сделать это, цикл обработки сообщений приложения должен включать в себя вызов функции TranslateAccelerator. Для получения дополнительной информации о клавишах - ускорителях, см. статью Ускорители клавиатуры.
Если поток использует немодальное диалоговое окно, цикл обработки сообщений должен включать в себя функцию IsDialogMessage так, чтобы блок диалога мог принимать ввод информации с клавиатуры.