Каким образом реализовано программирование на основе событий Win32 под капотом?

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

Я понимаю эту часть. Я не понимаю, что происходит между ними. В частности:

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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

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

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

В книгах Джеффри Рихтера много (всех?) деталей gory. Моя версия устарела (Advanced Windows). Текущая версия, по-видимому, называется Windows через C/С++.

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

Что значит "переводить" сообщение? Что действительно вызывает вызов TranslateMessage()?

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

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

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

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

Ответ 4

Не совсем положительно, но мое лучшее предположение говорит:

  • Очередь - это системный объект, к которому вы обращаетесь с помощью вызовов Win32 API. Это не в вашем адресном пространстве вашего процесса. Таким образом, обработчики прерываний могут получить к нему доступ (возможно, через HAL (Hardware Abstraction Layer) ядра).

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

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

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

Ответ 5

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