Функция окна описывает реакцию окна на поступающие сообщения. Она от обычных функций отличается следующим:
- имеет стандартные тип возврата и список формальных параметров;
- вызывается только операционной системой при поступлении сообщения окну;
- сообщения, которые не обрабатываются функцией окна, возвращаются операционной системе.
Есть еще одно отличие. В объектно-ориентированном программировании методы изменения параметров состояния объекта (функции-члены) обычно описывают отдельно. Функция окна реализует единственный метод для изменения всех параметров состояния окна.
Имя функции окна – это обычное имя, определяемое разработчиком. При регистрации класса операционная система запоминает указатель на эту функцию.
Рассмотрим пример описания функции окна.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
//Описание локальных переменных
static short cx, cy, left, top;
switch (msg) //Обработка сообщения
{
case WM_CREATE: {...; return 0;}
case WM_MOVE:
{ left = LOWORD(lParam);
top = HIWORD(lParam);
return 0;
}
case WM_SIZE:
{ cx = LOWORD(lParam);
cy = HIWORD(lParam);
return 0;
}
case WM_COMMAND: //Обрабатываем команды
{
switch (LOWORD(wParam))
{
case CM_FILE_EXIT:
{ DestroyWindow(hwnd); return 0; }
//Далее могут быть ветви других команд
}
return 0;
}
case WM_DESTROY:
{...; PostQuitMessage(0); return 0;}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Заголовок функции окна определен соглашениями Windows и имеет вид:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
Тип возврата LRESULT равноценен типу signed long. Модификатор CALLBACK указывает на соглашения о том, что эта функция вызывается операционной системой (такие функции называют функциями обратного вызова).
Имена типов UINT, WPARAM, LPARAM описаны следующим образом:
typedef unsigned int UINT;
typedef UINT WPARAM;
typedef LONG LPARAM;
Параметр hWnd – дескриптор окна-адресата, a msg, wParam и lParam описывают полученное сообщение. Например, параметр msg принимает код сообщения.
Рассмотрим, каким сообщениям соответствуют используемые в примере имена констант. В Windows описаны несколько сот кодов сообщений с префиксом WM_.
Код WM_CREATE поступает от функции CreateWindow (о ней речь пойдет ниже) перед созданием окна. Если после обработки этого сообщения функции CreateWindow возвращается значение -1, то окно не создается.
Код WM_SIZE функция окна получает после изменения размеров окна, a WM_MOVE – после перемещения левого верхнего угла рабочей области окна. Если при изменении размеров окна изменились координаты левого верхнего угла рабочей области, то функция окна сначала получает код WM_MOVE, а затем – WM_SIZE. После изменения режима отображения окна функция окна получает код WM_SIZE, а затем – WM_MOVE.
Код WM_COMMAND функция окна получает при поступлении команды. Тогда младшее слово параметра wParam содержит код команды. Разработчик свои сообщения часто связывает с командами меню и описывает идентификаторы для этих команд. Например, для идентификатора CM_FILE_EXIT команды меню текст приложения должен содержать макроопределение вида
#define CM_FILE_EXIT 3001
Код WM_DESTROY функции окна посылают перед разрушением окна. В примере функция окна, вызывая функцию DestroyWindow, сама себе отправляет сообщение WM_DESTROY.
Рассмотрим сообщения от мыши. Пусть курсор мыши находится над рабочей областью окна. После нажатия левой клавиши мыши функция окна получит код WM_LBUTTONDOWN, а правой клавиши – WM_RBUTTONDOWN. После отжатия левой (правой) клавиши функция окна получит код WM_LBUTTONUP (WM_RBUTTONUP). После перемещения курсора мыши функция окна получает код WM_MOUSEMOVE.
Можно получать сообщения от мыши, даже если курсор мыши не находится над рабочей областью окна. Для передачи мыши в монопольное использование окну hWnd вызывают функцию:
HWND SetCapture(HWND hWnd);
Эта функция возвращает дескриптор окна, у которого в монопольном пользовании была мышь, или NULL.
Вызов функции
void ReleaseCapture(void);
отменяет режим монопольного использования.
Значение параметра lParam зависит от кода сообщения.
При поступлении кода WM_MOVE параметр lParam содержит экранные координаты левого верхнего угла рабочей области. Например:
//Координата левого края рабочей области
left = LOWORD(lParam);
//Координата верхнего края рабочей области
top = HIWORD(lParam);
Для кода WM_SIZE параметр lParam несет информацию о ширине сх и высоте cy рабочей области:
cx = LOWORD(lParam); //Ширина рабочей области
cy = HIWORD(lParam); //Высота рабочей области
При поступлении любых сообщений от мыши расстояние курсора мыши от левого края рабочей области равно LOWORD(lParam), а от верхнего края – HIWORD(lParam).
Обратите внимание на описание локальных переменных. Если хотят, чтобы какие-либо переменные сохраняли свои значения до следующего вызова функции окна, то их описывают с приставкой static. Например, если функция окна многократно использует ширину сх и высоту сy рабочей области окна, то их описывают как static.
Вызов функции DefWindowProc означает, что необработанное сообщение возвращают операционной системе. Например, в данном примере не обрабатывают сообщения от мыши (как и многие другие получаемые сообщения). Эти сообщения, тем не менее, передаются функции окна, но она их возвращает операционной системе.
В тексте примера отсутствуют какие-либо действия. При необходимости можно включить некоторые действия, например в местах, обозначенных многоточиями.
Если функция окна обрабатывает код сообщения, то настоятельно рекомендуется вернуть определенное системой для этого кода значение.