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

Как уже говорилось, ОС Windows взаимодействует с приложениями посредством рассылки сообщений. Сообщения могут генерироваться как ОС, так и пользовательскими приложениями. ОС формирует сообщения при каждом входящем событии: при нажатии на клавиши, движении указателя мыши, нажатии на клавиши мыши и т.п.

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

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

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

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

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

Значения идентификаторов сообщений используются следующим образом:

· За ОС зарезервированы идентификаторы сообщений в диапазоне от 0х0000 до 0х03FF. В этом диапазоне находятся идентификаторы системных сообщений. Пользовательские приложения не могут использовать эти значения для своих сообщений.

· Значения в диапазоне от 0х0400 до 0х7FFF доступны для определения идентификаторов сообщений пользовательских классов окна.

· ОС возвращает идентификатор сообщения в виде числа из диапазона от 0хС000 до 0хFFFF в качестве результата работы функции RegisterWindowMessage. Использование этой функции исключает возможность конфликтов, возникающих если другое приложение попытается воспользоваться сообщением с тем же идентификатором для других целей.

ОС может передать сообщение оконной процедуре двумя способами: поместить сообщение в очередь сообщений или послать сообщение напрямую оконной процедуре.

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

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

Система помещает сообщение в очередь сообщений потока заполняя структуру типа MSG и затем копирует его с очередь сообщений. Структура данных MSG представлена в таблице 3.

Таблица 3 - Структура данных сообщения

MSG STRUC Название поля Тип в С Тип в ассемблере Назначение поля
  hwnd HWND DD переменная для хранения идентификатора окна, получающего сообщение
  message UINT DD идентификатор сообщения
  wparam WPARAM DD доп. информация о сообщении
  lparam LPARAM DD доп. информация о сообщении
  time DWORD DD время посылки сообщения
  pt POINT DD положение курсора мыши, во время посылки сообщения
MSG ENDS        

Приложение может удалить сообщение из своей очереди с помощью функции GetMessage.

После удаления сообщения из своей очереди, приложение заставляет ОС передать это сообщение оконной процедуре для обработки с помощью функции DispathMessage.

В качестве входного параметра, функция DispathMessage принимает указатель на структуру MSG, которая заполнена предыдущим вызовом функции GetMessage. Функция DispathMessage передает оконной процедуре дескриптор окна, идентификатор сообщения и 2 параметра сообщения, но не время посылки сообщения и позицию курсора мыши.

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

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

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

Простой цикл обработки сообщений содержит вызовы каждой из трех функций: GetMessage, TranslateMessage и DispatchMessage. При возникновении ошибки, функция GetMessage возвращает в качестве результата числов -1.

Функция GetMessage получает сообщение из очереди и копирует его в структуру MSG. Эта функция возвращает ненулевое значение до тех пор, пока не придет сообщение WM_QUIT, которое заставляет окончить цикл обработки сообщений. В однопоточных приложениях окончание цикла обработки сообщений зачастую является первым шагом в закрытии приложения. Приложение может закончить свой цикл обработки сообщений используя процедуру PostQuitMessage в ответ на сообщение WM_DESTROY, посылаемое оконной процедуре главного окна приложения.

Если определять дескриптор окна в качестве второго параметра функции GetMessage, то только сообщения, посланные данному окну будут выбираться из очереди. Функция GetMessage может также фильтровать сообщения в очереди, выбирая лишь те сообщения, которые попадают в определенный диапазон.

Цикл обработки сообщений потока должен включать в себя функцию TranslateMessage, если поток получает символы из клавитуры. ОС формирует сообщения виртуальных клавиш (WM_KEYDOWN и WM_KEYUP) всякий раз, когда пользователь нажимает клавишу. Сообщение виртуальной клавиши содержи код виртуальной клавиши, который определяет, какая клавиша была нажата, но не значение символа. Для получения этого значения, цикл обработки сообщений должен содержать функцию TranslateMessage, которая преобразует сообщения виртуальных клавиш в сообщения символов (WM_CHAR) и помещает их обратно в очередь сообщений приложения. Сообщение символа затем может быть удалено из цепочки итераций цикла обработки сообщений и обработано оконной процедурой.

Процедуры DispatchMessage посылает сообщения оконной процедуре, с которой окно связано с помощью структуры MSG.

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

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

Цикл обработки сообщений может модифицироваться в широком диапазоне. Можно извлекать сообщения из очереди без пересылки их в окно, можно извлекать только определенного рода сообщения и т.п.

Пример использования функций GetMessage, TranslateMessage, DispatchMessage можно найти в приложении А.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: