Написание процедуры окна
Функция DispatchMessage вызывает процедуру окна окна, которое является целью сообщения. Процедура окна имеет следующую подпись.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Существует четыре параметра:
- Hwnd — это дескриптор окна.
- UMsg — это код сообщения, например сообщение WM_SIZE указывает, что окно было изменено.
- wParam и lParam содержат дополнительные данные, относящиеся к сообщению. Точное значение зависит от кода сообщения.
LRESULT — это целочисленное значение, которое программа возвращает в Windows. Он содержит ответ вашей программы на определенное сообщение. Значение этого значения зависит от кода сообщения. CALLBACK — это соглашение о вызовах для функции.
Обычная процедура окна — это просто большая инструкция коммутатора, которая переключается на код сообщения. Добавьте варианты для каждого сообщения, которое требуется обрабатывать.
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:
- Создайте новый поток.
- Использование пула потоков.
- Используйте асинхронные вызовы ввода-вывода.
- Используйте асинхронные вызовы процедур.