Функция DispatchMessage вызывает процедуру окна, которое является адресатом сообщения. Процедура обработки окна имеет следующую сигнатуру.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Существует четыре параметра:
-
Hwnd — это дескриптор окна.
-
uMsg — это код сообщения; например, сообщение WM_SIZE указывает, что окно было изменено в размере.
-
wParam и lParam содержат дополнительные данные, относящиеся к сообщению. Точное значение зависит от кода сообщения.
LRESULT — это целочисленное значение, которое программа возвращает в Windows. Он содержит ответ вашей программы на определенное сообщение. Значение этого значения зависит от кода сообщения.
CALLBACK — это соглашение о вызовах для функции.
Обычная процедура обработки сообщений окна — это просто большой оператор switch, который переключает выполнение программы в зависимости от кода сообщения. Добавьте варианты для каждого сообщения, которое требуется обрабатывать.
switch (uMsg)
{
case WM_SIZE: // Handle window resizing
// etc
}
Дополнительные данные для сообщения содержатся в параметрах lParam и wParam. Оба параметра представляют собой целочисленные значения размера ширины указателя (32 бита или 64 бита). Значение каждого зависит от кода сообщения (uMsg). Для каждого сообщения необходимо будет найти код сообщения и привести параметры к правильному типу данных. Обычно данные являются числовым значением или указателем на структуру. Некоторые сообщения не имеют данных.
Например, в документации по сообщению WM_SIZE указано следующее:
-
wParam — это флаг, указывающий, было ли окно свернуто, максимизировано или изменено размер.
-
lParam содержит новую ширину и высоту окна в виде 16-разрядных значений, упакованных в один 32-или 64-разрядный номер. Чтобы получить эти значения, потребуется выполнить некоторые битовые сдвиги. К счастью, файл заголовка WinDef.h включает вспомогательные макросы, которые делают это.
Типичная процедура окна обрабатывает десятки сообщений, поэтому может стать довольно объёмной. Один из способов сделать код более модульным — поместить логику обработки каждого сообщения в отдельную функцию. В процедуре окна приведите параметры wParam и lParam к правильному типу данных и передайте эти значения в функцию. Например, чтобы обработать сообщение WM_SIZE , процедура окна будет выглядеть следующим образом:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
{
int width = LOWORD(lParam); // Macro to get the low-order word.
int height = HIWORD(lParam); // Macro to get the high-order word.
// Respond to the message:
OnSize(hwnd, (UINT)wParam, width, height);
}
break;
}
}
void OnSize(HWND hwnd, UINT flag, int width, int height)
{
// Handle resizing
}
Макросы LOWORD и HIWORD получают 16-разрядные значения ширины и высоты из lParam. Процедура окна извлекает ширину и высоту, а затем передает эти значения OnSize
функции.
Обработка сообщений по умолчанию
Если вы не обрабатываете определенное сообщение в процедуре окна, передайте параметры сообщения непосредственно в функцию DefWindowProc. Эта функция выполняет действие по умолчанию для сообщения, которое зависит от типа сообщения.
return DefWindowProc(hwnd, uMsg, wParam, lParam);
Избежание узких мест производительности в функциях окна
В то время как процедура обработки окна выполняется, она блокирует любые другие сообщения для окон, созданных в том же потоке. Поэтому избегайте длительной обработки в процедуре окна. Например, предположим, что программа открывает TCP-подключение и ожидает неограниченное время, пока сервер будет отвечать. Если вы делаете это в процедуре окна, интерфейс не будет реагировать до завершения запроса. В течение этого времени окно не может обрабатывать ввод мыши или клавиатуры, перерисовать себя или даже закрыть себя.
Вместо этого следует переместить работу в другой поток, используя одну из многозадаочных средств, встроенных в Windows:
- Создайте новое обсуждение.
- Используйте пул потоков.
- Используйте асинхронные вызовы ввода-вывода.
- Используйте асинхронные вызовы процедур.
Рисование окна