Сообщение окну можно либоPostMessage
). Соответственно, кто-то должен извлекать эти сообщения из очереди и передавать их окнам-адресатам. Это делается с помощью специального цикла, который называетсяGetMessage
(реже — PeekMessage
) и передаются в функцию DispatchMessage
. Эта функция определяет, какому окну предназначено сообщение, и вызывает его оконную процедуру. Таким образом, простейший цикл обработки сообщений выглядит так, как показано в листинге 1.5.
var
Msg: TMsg;
...
while GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
Блок-схема петли сообщений показана на рис. 1.4.
Рис 1.4. Блок-схема петли сообщений
Функция GetMessage
возвращает True
до тех пор, пока не будет получено сообщение WM_QUIT
, указывающее на необходимость завершения программы. Обычная программа для Windows, выполнив предварительные действия (регистрация класса и создание окна), входит в петлю сообщений, которую выполняет до конца своей работы. Все остальные действия выполняются в оконной процедуре при реакции на соответствующие сообщения.
Если нить не имеет петли сообщений, сообщения, которые посылаются нам, не будут обработаны. Это следует учитывать при создании таких компонентов, как, например, TTimer
и TClientSocket
. Эти компоненты создают невидимые окна для получения сообщений, которые необходимы им для работы. Если нить, создавшая эти объекты, не будет иметь петли сообщений, они будут неработоспособными
Сообщение, извлеченное из очереди, GetMessage
помещает в первый параметр-переменную типа TMsg
. Последние три параметра служат для фильтрации сообщений, позволяя извлекать из очереди только те сообщения, которые соответствуют определенным критериям. Если эти параметры равны нулю, как это обычно бывает, фильтрация при извлечении сообщений не производится.
Функция TranslateMessage
, которая обычно вызывается в петле сообщений, служит для трансляции клавиатурных сообщении (если петля сообщений реализуется только для обработки сообщении невидимым окнам, которые использует, например, COM/DCOM, или по каким-то другим причинам ввод с клавиатуры не обрабатывается или обрабатывается нестандартным образом, вызов TranslateMessage
можно опустить). Когда пользователь нажимает какую-либо клавишу на клавиатуре, система посылает окну, находящему в фокусе, сообщение WM_KEYDOWN
. Через параметры этого сообщения передаётся виртуальный код нажатой клавиши — двухбайтное число, которое определяется только положением нажатой клавиши на клавиатуре и не зависит от текущей раскладки, состояния клавиш TranslateMessage
. обнаружив такое сообщение, добавляет в очередь (причем не в конец, а в начало) сообщение WM_CHAR
, в параметрах которого передается код символа, соответствующего нажатой клавише, с учетом раскладки, состояния клавиш TranslateMessage
по виртуальному коду клавиши определяет код символа. При этом нажатие любой клавиши приводит к генерации WM_KEYDOWN
, а вот WM_CHAR
генерируется не для всех клавиш, а только для тех, которые соответствуют какому-то символу (например, не генерирует WM_CHAR
нажатие таких клавиш, как