Окно (window) — один из наиболее важных объектов в ОС Windows. Окно представляет собой прямоугольную область, в которой приложение отображает выводимую информацию и из которой получает вводимую. Кроме того, окно участвует и в программных интерфейсах — оно является получателем сообщений. Существует много разновидностей окон: диалоговые, окна многодокументных интерфейсов (MDI), окна сообщений, окна элементов управления. Присутствующие в системе окна образуют иерархию, в которой они могут находиться в отношениях владелец – подчиненный и предок – потомок. Окна имеют заголовки (Title, Caption), но в большинстве случаев обращение к ним происходит по описателям — Handle (системный тип HWND)
Класс окна (Window Class) определяет общие свойства и особенности поведения группы окон. Классы делятся на системные глобальные (к ним относятся, например, стандартные элементы управления), прикладные глобальные (реализуются в DLL, требуют регистрации, после чего могут использоваться любыми приложениями) и прикладные локальные (регистрируются как доступные единственному приложению). Именно класс связывает окно с его оконной процедурой. Классы идентифицируются, как правило, их именами.
Классы создаются и регистрируются функциями RegisterClass() и RegisterClassEx(). Создание окон любых видов обеспечивается функциями CreateWindow() и CreateWindowEx().
Оконная процедура (Window Procedure или WndProc) является получателем всех сообщений, поступающих окну. Обычно представляет собой конструкцию вида switch – case, распознающую поступившие сообщения и выполняющую их обработку:
LRESULT CALLBACK
MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case M_CLOSE: //команда на закрытие окна
DestroyWindow(hWnd);
break;
case WM_DESTROY: //подтверждение о готовности деинициализации
PostQuitMessage(0);
break;
case …
break;
default: //для всех остальных сообщений
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
Для данного примера правильнее было проверять адресата сообщений и начинать завершение приложения, только если это его главное окно.
Сообщения (Window Message) лежат в основе механизмов событийного управления приложениями. Они представляют собой структуры, передаваемые между приложениями и несущими информацию о событиях, команды, данные и так далее. Для представления сообщений служит структура MSG, поля которой содержат: тип сообщения, пару параметров wParam, lParam, адресата сообщения, время и экранные координаты его возникновения (имеет смысл для некоторых сообщений).
Сообщения передаются в приложение либо напрямую, либо через очередь. Прямая передача сообщения оконной процедуре является фактически косвенным вызовом этой процедуры, в том числе и из другого приложения. Для этого служит системная функция SendMessage(). Важно, что выполнение отправителя сообщения блокируется до завершения оконной процедуры.
Многие сообщения передаются не напрямую, а через очередь, что избавляет от взаимной зависимости и блокировок. Для этого служит функция PostMessage(). Кроме того, есть некоторые другие функции, совмещающие свойства синхронной и асинхронной отсылки, например SendNotifyMessage(), которая передает сообщение минуя очередь, но не ожидает окончания его обработки поэтому блокирующей не является.
Цикл обработки сообщений выбирает сообщения из очереди и перенаправляет их в соответствующие оконные процедуры. Цикл состоит упрощенно из трёх основных функций:
MSG msg;
while(GetMessage(&msg,NULL,0,0)) //выборка сообщений из очереди
{
TranslateMessage(&msg); //доп. обработка (трансляция) сообщения
DispatchMessage(&msg); //передача сообщения в оконную процедуру
}
Здесь выбираются все сообщения для всех окон приложения, однако параметры GetMessage() позволяют накладывать на них фильтры.
Функция GetMessage() является блокирующей — при отсутствии сообщений в очереди она переводит приложение в состояние ожидания. При наличии подходящего по фильтрам сообщения оно удаляется из очереди, и его содержимое переносится в структуру MSG. Функция возвращает нулевое значение при получении единственного сообщения WM_QUIT, для всех остальных — ненулевое. Как следствие, цикл прекращается после приема этого сообщения.
Упрощенно, типичное приложение Windows строится по следующей схеме:
1) WinMain() — головной модуль программы.
2) инициализация внутренних переменных и прочие подготовительные операции
3) RegisterClass() — регистрация локального класса
4) CreateWindow() — создание главного окна приложения (если требуется, могут быть и другие классы и окна
5) ShowWindow(), UpdateWindow() — отображение главного окна;
6) цикл обработки сообщений: GetMessage() — TranslateMessage() — DispatchMessage().
7) освобождение выделенных ресурсов, деинициализация внутренних переменных;
8) оконная процедура, прямых вызовов нет так как предполагается «обратный вызов» (Callback) со стороны системы.
Контрольные вопросы
1) Стандартная структура оконного приложения, его основные функции.
2) Окно. Функция создания нового окна и ее параметры.
3) Что такое оконный класс и каким образом он может быть создан.
4) Каким образом для окна можно указать собственные курсор и иконку.
5) За что отвечают функции UpdateWindow() и ShowWindow().
6) Сообщение Winmessage, его основные параметры. Очередь сообщений.
7) Способы отправки сообщений другому окну.
8) Цикл обработки сообщений. Функция GetMessage(), завершение цикла.
9) Функции TranslateMessage(), DispatchMessage().
10) Назначение, логика работы и параметры функции обработки сообщений.
11) Сообщение WM_PAINT. Функция вывода текста в окне и ее параметры.
12) Сообщение WM_COMMAND. Данные, передаваемые в wParam и lParam в данном сообщении.
13) Создание собственного пункта меню и обработка нажатия на него.
14) Функции GetWindowRect() и InvalidateRect().
15) Таймер. Каким образом таймер может быть создан и уничтожен. Как обрабатывать сообщения от таймера.