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

GetMessage

GetMessage — это функция Windows API, предназначенная для извлечения сообщения из очереди сообщений вызывающего потока. Она является одним из ключевых механизмов обработки сообщений в операционных системах семейства Microsoft Windows, обеспечивая взаимодействие между приложениями и системой, а также между различными частями одного приложения.

Назначение и принцип работы

Функция GetMessage служит для получения сообщения, адресованного окну, принадлежащему текущему потоку. Сообщения в Windows представляют собой структурированные данные, информирующие приложение о различных событиях: нажатии клавиш, перемещении мыши, изменении размеров окна, таймерах, пользовательских командах и т.д. Каждое сообщение содержит идентификатор (тип сообщения), параметры (wParam и lParam), время отправки и координаты курсора.

Очередь сообщений — это системный объект, связанный с каждым потоком, который создал хотя бы одно окно. Сообщения помещаются в очередь операционной системой или другими приложениями. GetMessage извлекает сообщения из этой очереди в порядке их поступления (FIFO — first in, first out). Если очередь пуста, функция блокирует выполнение потока, ожидая поступления нового сообщения. Это позволяет приложению не тратить процессорное время вхолостую, а переходить в состояние ожидания.

Синтаксис и параметры

Прототип функции на языке C (из заголовочного файла windows.h) выглядит следующим образом:

``c BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax ); ``

Параметры:

  • lpMsgуказатель на структуру MSG, в которую функция записывает полученное сообщение. Структура содержит поля: hwnd (дескриптор окна-получателя), message (идентификатор сообщения), wParam и lParam (дополнительные параметры), time (время отправки), pt (координаты курсора в момент отправки).
  • hWnd — дескриптор окна, для которого извлекаются сообщения. Если NULL, функция извлекает сообщения для всех окон текущего потока, а также сообщения потока (например, WM_QUIT). Если задан конкретный дескриптор, извлекаются только сообщения, адресованные этому окну.
  • wMsgFilterMin и wMsgFilterMax — диапазон идентификаторов сообщений, которые должны быть извлечены. Если оба параметра равны нулю, функция извлекает все сообщения. Если задан диапазон, извлекаются только сообщения с идентификаторами в этом интервале (включая границы).

Возвращаемое значение: ненулевое значение, если извлечено сообщение, отличное от WM_QUIT. Ноль — если извлечено сообщение WM_QUIT, сигнализирующее о завершении работы приложения. В случае ошибки возвращается -1.

Типичное использование в цикле сообщений

Основное применение GetMessage — в главном цикле обработки сообщений приложения (message loop). Классический пример на C/C++:

``c MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; ``

Здесь:

  • GetMessage извлекает сообщение из очереди.
  • TranslateMessage преобразует виртуальные коды клавиш в символьные сообщения (например, WM_CHAR).
  • DispatchMessage отправляет сообщение оконной процедуре (callback-функции окна), которая обрабатывает его.
  • Цикл продолжается до тех пор, пока GetMessage не вернет 0 при получении WM_QUIT, после чего приложение завершается.

Этот цикл является основой для всех GUI-приложений Windows, работающих с оконной системой. Без него окна не будут получать и обрабатывать сообщения, что приведет к «зависанию» интерфейса.

Сравнение с другими функциями

В Windows API существуют альтернативные функции для работы с очередью сообщений:

  • PeekMessage — извлекает сообщение, если оно есть, но не блокирует поток при пустой очереди. Возвращает TRUE, если сообщение было извлечено, и FALSE в противном случае. Используется, когда приложению нужно выполнять фоновую работу, не блокируя поток полностью.
  • WaitMessage — приостанавливает поток до появления нового сообщения в очереди, но не извлекает его. Позволяет эффективно ожидать событий.
  • GetQueueStatus — возвращает флаги, указывающие на наличие сообщений определённых типов в очереди, без их извлечения.

GetMessage отличается от PeekMessage тем, что блокирует поток, что экономит ресурсы процессора. Однако в современных приложениях с асинхронными операциями (например, на основе async/await в C# или std::async в C++) использование блокирующих вызовов может быть нежелательным, и разработчики часто прибегают к PeekMessage в сочетании с неблокирующими циклами.

История и развитие

Функция GetMessage появилась в первых версиях Windows (Windows 1.0, 1985 год) как часть базового API для кооперативной многозадачности. В то время все приложения работали в одном адресном пространстве, и GetMessage была основным механизмом переключения между задачами: когда одно приложение вызывало GetMessage и очередь была пуста, управление передавалось другому приложению.

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

В Windows 8 и более поздних версиях появилась альтернативная модельCoreDispatcher для приложений UWP (Universal Windows Platform), которая не использует GetMessage напрямую, но концептуально основана на той же идее очереди сообщений.

Особенности и ограничения

  • Блокировка потока: GetMessage блокирует поток, пока не появится сообщение. Это может быть проблемой в приложениях, требующих высокой отзывчивости или выполняющих длительные вычисления в основном потоке. Для таких случаев используют многопоточность или PeekMessage.
  • Только для оконных потоков: Функция работает только в потоках, которые создали хотя бы одно окно. В противном случае очередь сообщений не создаётся, и вызов GetMessage может привести к неопределённому поведению.
  • Сообщение WM_QUIT: Это специальное сообщение, которое не обрабатывается оконной процедурой, а завершает цикл сообщений. Оно помещается в очередь вызовом PostQuitMessage.
  • Фильтрация сообщений: Параметры wMsgFilterMin и wMsgFilterMax позволяют извлекать только определённые типы сообщений, что может быть полезно для оптимизации, но редко используется в типовых циклах.

Применение в современных технологиях

Несмотря на возраст, GetMessage остаётся актуальной. Она используется:

  • В классических Win32-приложениях (C++, Delphi, PureBasic).
  • В библиотеках и фреймворках, абстрагирующих оконную систему (например, Qt, wxWidgets, MFC) — они часто реализуют собственный цикл сообщений поверх GetMessage.
  • В некоторых компонентах .NET Framework (Windows Forms) — внутренняя обработка сообщений также опирается на GetMessage.
  • В играх и приложениях, использующих DirectX или OpenGL, где оконная система Windows всё равно требует цикла сообщений для обработки ввода и системных событий.

Критика и альтернативы

Основная критика GetMessage связана с её блокирующим характером и привязкой к модели «одно окно — один поток». В современных подходах, таких как реактивное программирование или асинхронные паттерны, блокировка основного потока считается антипаттерном. Альтернативы включают:

  • Использование PeekMessage в цикле с проверкой на пустоту очереди (например, в игровых движках для поддержания высокой частоты кадров).
  • Применение MsgWaitForMultipleObjects для ожидания сообщений или других объектов синхронизации (например, дескрипторов событий).
  • Переход на модели, не требующие цикла сообщений, такие как Windows.Devices.Input в UWP или System.Threading.Channels в .NET.

Тем не менее, для большинства традиционных настольных приложений GetMessage остаётся стандартом де-факто.

Интересные факты

  • В ранних версиях Windows функция GetMessage могла возвращать управление другим приложениям, что было основой кооперативной многозадачности. Разработчики могли «завесить» систему, если их приложение не вызывало GetMessage достаточно часто.
  • Сообщение WM_QUIT имеет идентификатор 0x0012 и не может быть отправлено обычным способом через PostMessage или SendMessage — для него существует специальная функция PostQuitMessage.
  • В 64-битных версиях Windows структура MSG имеет размер 48 байт (в 32-битных — 28 байт), что связано с увеличением размера указателей и дескрипторов.

Источники

  • Microsoft Docs: «GetMessage function (winuser.h)» — официальная документация Windows API.
  • Charles Petzold, «Programming Windows» (5th edition) — классическое руководство по Win32 API.
  • Jeffrey Richter, «Programming Applications for Microsoft Windows» — углублённое описание механизмов сообщений.
  • Архив MSDN Library — раздел «Messages and Message Queues».

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

На главную BFOmetr →