Как работает очередь сообщений в Win32? - PullRequest
5 голосов
/ 11 февраля 2012

Я прочитал кое-что о Win32 и о том, как работает цикл сообщений, и есть кое-что, что мне до сих пор неясно: что именно хранится в очереди сообщений? Целочисленное значение, которое соответствует сообщению (WM_COMMAND, WM_CREATE и т. Д.) Или указателю на структуру MSG, содержащую целочисленное значение сообщения и другие данные, такие как wParam, lParam и т. Д.?

Ответы [ 3 ]

12 голосов
/ 11 февраля 2012

Чтобы ответить на ваш вопрос узко, каждое сообщение в очереди хранит, как минимум,

  • дескриптор окна, на которое направлено сообщение,
  • код сообщения, wParamи lParam, как вы уже правильно заметили,
  • время публикации сообщения, которое вы извлекаете с помощью GetMessageTime(),
  • для сообщений интерфейса пользователя, положение курсора, когда сообщение было отправлено (см. GetMessagePos()).

Обратите внимание, что не все сообщения фактически сохраняются в очереди.Сообщения, которые отправляются с SendMessage() в окно из потока, которому принадлежит окно, никогда не сохраняются;вместо этого функция сообщения окна получателя вызывается напрямую.Сообщения, отправленные из других потоков, сохраняются до их обработки, и поток-отправитель блокируется до тех пор, пока на сообщение не будет получен ответ, либо путем выхода из оконной функции, либо явным образом с вызовом ReplyMessage().Функция API InSendMessage() помогает выяснить, обрабатывает ли функция Windows сообщение, отправленное из другого потока.

Сообщения, которые вы или системная публикация, сохраняются в очереди, за некоторыми исключениями.

  • Сообщения WM_TIMER фактически никогда не сохраняются сохраняются ;вместо этого GetMessage() создает сообщение таймера, если в очереди нет других сообщений и таймер созрел.Это означает, что, во-первых, сообщения таймера имеют самый низкий приоритет удаления из очереди, и, во-вторых, что несколько сообщений из таймера с коротким периодом никогда не будут переполнены очередью, даже если GetMessage() некоторое время не вызывается.В результате для данного таймера отправляется одиночное сообщение WM_TIMER, даже если таймер сработал несколько раз с момента обработки последнего сообщения WM_TIMER от этого таймера.

  • Аналогично, WM_QUIT также не сохраняется, а только помечается.GetMessage() делает вид, что получил WM_QUIT после того, как очередь исчерпана, и это последнее полученное сообщение.

  • Другой пример - сообщение WM_PAINT (подсказка @ cody-серый за напоминание об этом).Это сообщение также имитируется, когда любая часть окна помечается как «грязная» и требует перекраски.Это также сообщение с низким приоритетом, созданное таким образом, что несколько недействительных областей в окне перекрашиваются одновременно, когда очередь становится пустой, чтобы уменьшить отзывчивость GUI и уменьшить мерцание.Вы можете принудительно перекрасить, позвонив по номеру UpdateWindow().Эта функция действует как SendMessage(), в том смысле, что она не возвращается, пока открытая часть окна не будет фактически перерисована.Эта функция не отправляет WM_PAINT окну, если недопустимая область этого окна пуста, в качестве очевидной оптимизации.

Возможно, существуют другие исключения ивнутренние оптимизации.

Сообщения, отправленные с PostMessage(), попадают в очередь потока, которому принадлежит окно, в которое отправляется сообщение.

В какой форме сообщения хранятся внутри, мыне знаю и нам пофиг.Windows API абстрагирует это полностью.Структура MSG заполняется в памяти, которую вы передаете GetMessage() или PeekMessage().Вам не нужно знать или беспокоиться о деталях внутренней реализации помимо тех, которые описаны в руководствах по Windows SDK.


¹ Я не знаю, как именно WM_PAINT и WM_TIMER имеют приоритет относительно друг друга.Я предполагаю, что WM_PAINT имеет более низкий приоритет, но я могу ошибаться.

9 голосов
/ 11 февраля 2012

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

  • Сообщения, доставляемые SendMessage ().Windows напрямую вызывает оконную процедуру, сообщение не возвращается Peek / GetMessage (), но для ее отправки требуется вызов этой функции.На сегодняшний день большинство сообщений доставляется таким образом.WM_COMMAND похож на это, он напрямую отправляется кодом, который транслирует событие нажатия клавиши, например TranslateAccelerator ().Нет поведения, подобного очереди.

  • Сообщения, которые синтезируются из состояния окна.Лучшими примерами являются WM_PAINT, предоставляемые, когда установлен флаг состояния «окно имеет грязный прямоугольник».И WM_TIMER, доставляется, когда установлен флаг состояния «таймер истек».Это сообщения с низким приоритетом, которые доставляются только тогда, когда очередь сообщений пуста.Они доставляются с помощью GetMessage (), но в противном случае они не находятся в очереди.

  • Ввод сообщений о событиях для клавиатуры и мыши.Это сообщения, которые действительно имеют поведение, подобное очереди.Для клавиатуры это гарантирует, что ввод с опережением работает, никакое нажатие клавиши не теряется, когда программа не готова принять нажатие клавиши.С ним связана группа состояний, например, копируется все состояние клавиатуры.Примерно то же самое для мыши, за исключением того, что там меньше состояния.Сообщение WM_MOUSEMOVE является интересным угловым случаем, очередь не хранит каждый пиксель, пройденный курсором.Изменения позиции накапливаются в одном сообщении, сохраняются или доставляются при необходимости.

  • Сообщения, хранящиеся в очереди с помощью явного вызова PostMessage ().Это полностью зависит от программного кода, очевидно, ему нужно хранить только аргументы вызова плюс время выполнения вызова, чтобы его можно было точно воспроизвести во время GetMessage ().

0 голосов
/ 11 февраля 2012

MSDN имеет хорошую статью здесь , объясняющую все о сообщениях и очередях сообщений.

Но чтобы ответить на ваш вопрос, Очередь существует для каждого окна, она временно хранит сообщения и их параметры, независимо от того, определена ли для них очередь из MSG, но скорее всего(или что-то подобное).Следует также отметить, что не все сообщения попадут в очередь, некоторые требуют немедленной обработки.

...