Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

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

при организации петли сообщений следует принимать меры против рекурсии. Например, в случае с кнопкой в обработчике ее нажатие можно запретить (
Enabled := False
), и вновь разрешить только после окончания обработки, тогда пользователь не сможет нажать кнопку во время работы локальной петли сообщений. В очередь можно поставить сообщение, не привязанное ни к какому окну. Это делается с помощью функции
PostThreadMessage
. Такие сообщения необходимо самостоятельно обрабатывать в петле сообщений, потому что функция
DispatchMessage
их просто игнорирует.

Рис. 1.6. Блок-схема программы с локальной петлей сообщений

Существуют также широковещательные сообщения, которые посылаются сразу нескольким окнам. Проще всего послать такое сообщение с помощью функции

PostMessage
, указав в качестве адресата не дескриптор конкретного окна, а константу
HWND_BROADCAST
. Такое сообщение получат все окна, расположенные непосредственно на рабочем столе и не имеющие при этом владельцев (в терминах системы). Существует также специальная функция
BroadcastSystemMessage
(начиная с Windows ХР — ее расширенный вариант
BroadcastSystemMessageEx
), которая позволяет уточнить, каким конкретно окнам будет отправлено широковещательное сообщение.

Кроме параметров

wParam
и
lParam
, каждому
сообщению
приписывается время отправки и координаты курсора в момент возникновения. Соответствующие поля есть в структуре TMsg, которую используют функции
GetMessage
и DispatchMessage, но у оконной процедуры не предусмотрены параметры для их передачи. Получить время отправки сообщения и координаты курсора при обработке сообщения можно с помощью функций
GetMessageTime
и
GetMessagePos
соответственно.

Существует также ряд функций, которые могут обрабатывать сообщения без участия

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

□ 

TranslateAccelerator
— на основе загруженной из ресурсов таблицы распознает нажатие "горячих" клавиш меню и вызывает оконную процедуру, передавая ей сообщение
WM_COMMAND
или
WM_SYSCOMMAND
, аналогичное тому, которое посылается при выборе соответствующего пункта меню пользователем;

□ 

TranslateMDISysAccel
— аналог предыдущей функции за исключением того, что распознает "горячие" клавиши системного меню MDI-окон;

□ 

IsDialogMessage
— распознает сообщения, имеющие особый смысл для диалоговых окон (например, нажатие клавиши <Tab> для перехода между элементами управления). Используется для немодальных диалоговых окон и окон, не являющихся диалоговыми (т.е. созданными без помощи функций
CreateDialogXXXX
), но требующими аналогичной функциональности.

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

показывает, как будет выглядеть петля сообщений, содержащая вызов
TranslateAccelerator
для родительской MDI-формы и
TranslateMDISysAccel
для дочерней.

Листинг 1.6. Петля сообщении с обработкой "горячих" клавиш главного меню и системного меню MDI-окон

while GetMessage(Msg, 0, 0, 0) do

 if not TranslateMDISysAccel(ActiveMDIChildHandle, Msg)

and not TranslateAccelerator(MDIFormHandle, AccHandle, Msg) then

 begin

TranslateMessage(Msg);

DispatchMessage(Msg);

 end;

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

SendMessage
. Если эта функция вызывается из той же нити, которой принадлежит окно-адресат, то фактически это эквивалентно прямому вызову оконной процедуры. Если окно принадлежит другой нити, данное сообщение становится в отдельную очередь, имеющую более высокий приоритет, чем очередь для посланных сообщений. Функции
GetMessage
и
PeekMessage
сначала выбирают все сообщения из этой очереди и отправляют их на обработку, и лишь затем приступают к анализу очереди посланных сообщений.

Примечание

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

GetMessage
или
PeekMessage
, то эти сообщения не попадают в функции
TranslateMDISysAccel
,
TranslateAccelerator
и
TranslateMessage
. Это необходимо учитывать при передаче окну сообщений, эмулирующих нажатие клавиш на клавиатуре. Такие сообщения окну нужно посылать, а не отправлять, чтобы они прошли полный цикл обработки и окно правильно на них отреагировало. Для эмуляции сообщений от клавиатуры можно также воспользоваться функцией
keybd_event
, но она посылает сообщение не указанному окну, а активному, что не всегда удобно.

Диалоговые окна обрабатывают сообщения по-особому. Эти окна делятся на модальные (создаются и показываются с помощью функций

DialogBoxXXXX
) немодальные (создаются с помощью функций
CreateDialogXXXX
и затем показываются с помощью функции
ShowWindow
, использующейся и для обычных, не диалоговых, окон). И модальные, и немодальные окна создаются на основ шаблона, который может храниться в ресурсах приложения или в памяти. В шаблоне можно явно указать имя созданного вами оконного класса диалогового окна или (как это обычно бывает) не указывать его вообще, чтобы был выбран класс, предоставляемый системой для диалоговых окон по умолчанию. Оконная процедура диалогового класса должна передавать необработанные сообщения функции
DefDlgProc
.

Все диалоговые окна имеют так называемую диалоговую процедуру — функцию, указатель на которую передается в качестве одного из параметров функциям

DialogВохХХХХ
и
CreateDialogXXXX
. Прототипы диалоговой и оконной процедур совпадают. Функция
DefDlgProc
начинаем свою работу с того, что вызывает диалоговую процедуру. Если та не обработала переданное ей сообщение (о чем сигнализирует возвращаемое нулевое значение), функция
DefDlgProc
обрабатывает его сама. Таким образом, с помощью одного оконного класса и одной оконной процедуры можно реализовывать различные диалоговые окна, используя разные диалоговые процедуры.

Поделиться:
Популярные книги

Возвращение Безумного Бога 5

Тесленок Кирилл Геннадьевич
5. Возвращение Безумного Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Возвращение Безумного Бога 5

Холодный ветер перемен

Иванов Дмитрий
7. Девяностые
Фантастика:
попаданцы
альтернативная история
6.80
рейтинг книги
Холодный ветер перемен

Кровь, золото и помидоры

Распопов Дмитрий Викторович
4. Венецианский купец
Фантастика:
альтернативная история
5.40
рейтинг книги
Кровь, золото и помидоры

Наследник павшего дома. Том I

Вайс Александр
1. Расколотый мир
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник павшего дома. Том I

Книга 5. Империя на марше

Тамбовский Сергей
5. Империя у края
Фантастика:
альтернативная история
5.00
рейтинг книги
Книга 5. Империя на марше

Генерал Скала и сиротка

Суббота Светлана
1. Генерал Скала и Лидия
Любовные романы:
любовно-фантастические романы
6.40
рейтинг книги
Генерал Скала и сиротка

Мимик нового Мира 14

Северный Лис
13. Мимик!
Фантастика:
юмористическое фэнтези
постапокалипсис
рпг
5.00
рейтинг книги
Мимик нового Мира 14

Стрелок

Астахов Евгений Евгеньевич
5. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Стрелок

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Сержант. Назад в СССР. Книга 4

Гаусс Максим
4. Второй шанс
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Сержант. Назад в СССР. Книга 4

Третий. Том 2

INDIGO
2. Отпуск
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий. Том 2

Боксер 2: назад в СССР

Гуров Валерий Александрович
2. Боксер
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Боксер 2: назад в СССР

Вопреки судьбе, или В другой мир за счастьем

Цвик Катерина Александровна
Любовные романы:
любовно-фантастические романы
6.46
рейтинг книги
Вопреки судьбе, или В другой мир за счастьем

Кротовский, сколько можно?

Парсиев Дмитрий
5. РОС: Изнанка Империи
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Кротовский, сколько можно?