Как в Win32 реализовано программирование на основе событий? - PullRequest
11 голосов
/ 19 апреля 2009

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

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

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

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

Ответы [ 5 ]

6 голосов
/ 19 апреля 2009

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

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

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

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

6 голосов
/ 20 апреля 2009

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

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

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

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

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

4 голосов
/ 14 мая 2009

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

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

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

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

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

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

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

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

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

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

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

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

1 голос
/ 20 апреля 2009

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

1 голос
/ 19 апреля 2009

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...