Открыть сервис

Оконная процедура

Оконная процедура — в вычислительной технике и программировании функция обратного вызова (callback), которая обрабатывает сообщения, отправляемые операционной системой окну приложения. Является центральным элементом событийно-ориентированной архитектуры графического интерфейса пользователя (GUI) в операционных системах семейства Microsoft Windows. Каждое окно в системе, независимо от его типа (главное окно, дочерний элемент управления, диалоговое окно), ассоциировано с оконной процедурой, которая определяет его поведение при получении различных событий: отрисовке, нажатии клавиш, перемещении мыши, изменении размеров, завершении работы.

Принцип работы

Оконная процедура является частью модели сообщений Windows. Операционная система помещает сообщения, адресованные определённому окну, в очередь сообщений потока, которому принадлежит окно. Цикл обработки сообщений (message loop) приложения извлекает эти сообщения и диспетчеризует их, вызывая соответствующую оконную процедуру. Процедура получает четыре параметра: дескриптор окна (HWND), идентификатор сообщения (UINT) и два параметра (WPARAM и LPARAM), содержащие дополнительные данные, специфичные для каждого типа сообщения.

Оконная процедура обязана обработать все сообщения, которые она получает. Для сообщений, не требующих специальной обработки, процедура должна вызывать функцию DefWindowProc, которая обеспечивает стандартное поведение окна (например, закрытие при нажатии Alt+F4, изменение размеров при перетаскивании границ). Если процедура не вызывает DefWindowProc для необработанных сообщений, окно может вести себя некорректно или не реагировать на действия пользователя.

Типы оконных процедур

Главная оконная процедура

Определяет поведение основного окна приложения. Обрабатывает сообщения, связанные с созданием окна (WM_CREATE), его уничтожением (WM_DESTROY), изменением размеров (WM_SIZE), перерисовкой (WM_PAINT) и завершением работы (WM_CLOSE). В этой процедуре обычно располагается основная логика приложения.

Процедура диалогового окна

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

Процедура подкласса

Механизм, позволяющий перехватывать и изменять поведение существующего окна или элемента управления без создания нового класса окна. Подкласс устанавливается с помощью функции SetWindowLongPtr или SetClassLongPtr. Новая процедура получает сообщения до того, как они будут обработаны исходной процедурой, что позволяет модифицировать поведение стандартных элементов (например, кнопок, полей ввода).

Процедура суперкласса

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

Регистрация и создание

Для того чтобы окно могло использовать оконную процедуру, необходимо зарегистрировать класс окна. Класс окна определяется структурой WNDCLASS (или WNDCLASSEX), в которой указывается имя класса, дескриптор экземпляра приложения, значок, курсор, цвет фона и, что наиболее важно, адрес оконной процедуры (lpfnWndProc). После регистрации класса с помощью функции RegisterClass (или RegisterClassEx) можно создавать окна этого класса, вызывая CreateWindow или CreateWindowEx. При создании окна система связывает с ним указанную оконную процедуру.

Обработка сообщений

Оконная процедура реализуется как функция с фиксированной сигнатурой:

``c LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); ``

Типичная структура процедуры включает оператор switch, который анализирует значение uMsg — идентификатор сообщения. Для каждого обрабатываемого сообщения выполняется соответствующий код. Наиболее часто обрабатываемые сообщения:

  • WM_CREATE — отправляется при создании окна. Используется для инициализации данных, создания дочерних элементов управления.
  • WM_PAINT — сигнализирует о необходимости перерисовки клиентской области окна. В обработчике обычно вызываются BeginPaint, функции рисования (например, TextOut, Rectangle) и EndPaint.
  • WM_DESTROY — отправляется при уничтожении окна. В обработчике часто вызывается PostQuitMessage, чтобы завершить цикл сообщений приложения.
  • WM_CLOSE — отправляется при попытке закрыть окно. Позволяет выполнить проверки или подтверждение перед закрытием.
  • WM_SIZE — указывает на изменение размеров окна. Используется для пересчёта расположения элементов управления.
  • WM_COMMAND — отправляется при активации элемента управления (например, нажатии кнопки) или выборе пункта меню. Содержит идентификатор команды.
  • WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_KEYDOWN — сообщения от устройств ввода.

Особенности реализации

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

История

Концепция оконной процедуры была введена в Windows 1.0 (1985 год) как часть кооперативной многозадачной модели. В ранних версиях все приложения выполнялись в одном потоке, и оконные процедуры должны были быстро возвращать управление системе. С появлением Windows NT и Windows 95 модель стала вытесняющей, но принцип оконной процедуры остался неизменным. В современных версиях Windows (начиная с Windows Vista) оконные процедуры могут обрабатывать сообщения в контексте нескольких потоков, однако базовая архитектура сохранилась.

Альтернативы и развитие

В современных фреймворках (Windows Forms, WPF, UWP, WinUI) разработчики редко работают с оконными процедурами напрямую. Эти технологии предоставляют абстракции более высокого уровня — события, обработчики событий, модель компоновки. Однако под капотом все они используют оконные процедуры, создаваемые автоматически. Для низкоуровневой разработки на C или C++ с использованием WinAPI знание оконных процедур остаётся необходимым.

Пример простейшей оконной процедуры

Ниже приведён пример процедуры для окна, которое выводит текст «Hello, World!» в клиентской области:

``c LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; switch (uMsg) { case WM_PAINT: hdc = BeginPaint(hwnd, &ps); TextOut(hdc, 10, 10, L"Hello, World!", 13); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } ``

Этот код обрабатывает только два сообщения: перерисовку и уничтожение окна. Все остальные сообщения передаются функции по умолчанию.

Источники

  • Charles Petzold. «Programming Windows» (5th edition). Microsoft Press, 1998.
  • MSDN Library. «Window Procedures». Microsoft Docs.
  • Jeffrey Richter. «Windows via C/C++». Microsoft Press, 2007.
  • Документация Microsoft по WinAPI (раздел «Window Messages»).

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →