Как программирование, управляемое событиями, в Win32 реализовано «под капотом»?

StackOverflow https://stackoverflow.com/questions/765421

Вопрос

В приложении Win32 C++ мы запускаем цикл обработки сообщений, который извлекает сообщения из очереди, преобразует их и затем отправляет.В конце концов, каждое сообщение достигает нашего WndProc, где можно обработать соответствующее событие.

Я понимаю эту часть.Чего я не понимаю, так это того, что происходит между ними.Конкретно:

  1. Различные типы обработчиков прерываний ОС должны помещать сообщения в указанную «очередь сообщений», но где в адресном пространстве процесса находится эта очередь?Как он подвергается воздействию кода обработчика прерываний?
  2. Что значит «перевести» сообщение?Что означает вызов TranslateMessage() действительно?
  3. После отправки DispatchMessage(), какие места проходит сообщение, прежде чем достичь моего WndProc (т.что с этим делает ОС)?

Если кто-нибудь знает ответы на вышеизложенное, пожалуйста, удовлетворите мое любопытство.Спасибо.

Это было полезно?

Решение

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

Приложения могут иметь собственную очередь для обработки сообщений.Эти очереди создаются по запросу (только при необходимости).

Перевод сообщения используется для создания сообщений, которые не являются «реальными» событиями.Например, сообщение WM_CONTEXTMENU «переводится» либо при щелчке правой кнопкой мыши, либо при нажатии клавиши контекстного меню, либо при нажатии клавиши Shift-F10.WM_CHAR транслируется из сообщений WM_KEYDOWN.И, конечно же, многие другие сообщения «переводятся» таким же образом.

Сообщение отправляется в каждое окно, которое должно его получить.В зависимости от типа сообщения ОС решает, должно ли окно получать это сообщение или нет.Большинство сообщений ожидаются системой, т. е. сообщение не будет отправлено в другое окно, пока оно не будет обработано этим окном.Это оказывает большое влияние на широковещательные сообщения:если одно окно не возвращается при обработке этого сообщения, очередь заблокирован и другие окна больше не будут получать сообщение.

Другие советы

Это зависит от того, как ваше сообщение отправляется и как оно обрабатывается.

Когда вы вызываете SendMessage, если целевое окно принадлежит текущему потоку, вызов обходит очередь сообщений для окна, и оконный менеджер напрямую вызывает windowproc в целевом окне.Если целевое окно принадлежит другому потоку, оконный менеджер фактически вызывает PostMessage и перекачивает оконные сообщения до тех пор, пока целевое окно не вернется из оконной процедуры.

Когда вы вызываете PostMessage, оконный менеджер маршалирует параметры сообщения и вставляет соответствующий объект в очередь сообщений для целевого окна.При следующем вызове GetMessage сообщение удаляется из очереди сообщений.

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

Как указал Стефан, TranslateMessage просто переводит клавиши быстрого доступа - например, он преобразует последовательности клавиш в сообщения WM_COMMAND.

Различные типы обработчиков прерываний ОС должны помещать сообщения в указанную «очередь сообщений», но где в адресном пространстве процесса находится эта очередь?Как он подвергается воздействию кода обработчика прерываний?

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

Опубликованные сообщения помещаются непосредственно в очередь потоков для целевого окна.

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

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

В книгах Джеффри Рихтера есть много (все?) кровавых подробностей.Моя редакция старая (Advanced Windows).Нынешнее издание, кажется, называется Windows через C/C++.

ОС проделывает МНОГО работы, чтобы поток сообщений выглядел рациональным (и относительно простым) для вызывающего абонента.

Что значит «перевести» сообщение?Что на самом деле делает вызов TranslateMessage()?

Он отслеживает сообщения виртуальных клавиш и, когда распознает комбинацию нажатия/нажатия клавиш, добавляет символьные сообщения.Если ты не позвонишь ПеревестиСообщение, вы не будете получать символьные сообщения, такие как WM_CHAR.

Я подозреваю, что он отправляет символьное сообщение непосредственно перед возвратом (а не публикует его).Я никогда не проверял, но, кажется, помню, что сообщения WM_CHAR приходят непосредственно перед WM_KEYUP.

После отправки DispatchMessage(), через какие места проходит сообщение, прежде чем достичь моего WndProc (т.что с этим делает ОС)?

DispatchMessage передает сообщение в WndProc для целевого окна.Попутно некоторые перехватчики могут получить возможность увидеть сообщение (и, возможно, помешать ему).

Чтобы ответить на последний подвопрос, отправленное сообщение будет отправлено в ваш WindowProc после того, как оно пройдет через все перехватчики (WH_CALLWNDPROC).

Я не совсем уверен в этом, но мое лучшее предположение гласит:

  1. Очередь — это системный объект, к которому вы обращаетесь с помощью вызовов API Win32.Он вообще не находится в адресном пространстве вашего процесса.Таким образом, обработчики прерываний могут получить к нему доступ (вероятно, через HAL (уровень аппаратной абстракции) ядра).

  2. В Win16 этот вызов взял различные части более крупного сообщения и объединил их в одно целое.Таким образом, TranslateMessage добавит WM_KEYPRESS, когда обнаружит соответствующую последовательность WM_KEYDOWN WM_KEYUP.Это также превратило бы различные сообщения о нажатии кнопок в сообщения двойного щелчка на основе внутренних настроек и временных меток сообщений.Я не знаю, делает ли это все еще в Win32.

  3. DispatchMessage, вероятно, является местом обработки перехватчиков сообщений Window.Поэтому, если в вашем окне есть перехватчик, он вызывается либо здесь, либо при вызове GetMessage.Я не уверен.Помимо этого, DispatchMessage просто ищет адрес WndProc, связанный с окном, и вызывает его.Больше делать нечего.

Надеюсь, это поможет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top