Синхронная посылка сообщений

Синхронная посылка выполняется с помощью функции:

LRESULT SendMessage( // Синхронная посылка окну или нити

HWND hWnd, // хэндл окна-приемника

UINT Msg, // тип сообщения

WPARAM wParam, // первый параметр сообщения

LPARAM lParam // второй параметр сообщения

);

Принципиальное отличие от асинхронной посылки заключается в том, что нить, пославшая сообщение, не возобновляет свою работу до тех пор, пока не будет получено подтверждение окончания обработки сообщения. Кроме того, при обработке некоторых типов сообщений программа может выдавать определенные данные в качестве ответа на сообщение. Для передачи ответа может использоваться либо результат, возвращаемый функцией SendMessage, либо содержимое области памяти, адресуемой одним из параметров сообщения. Выше отмечалось, например, что в ответ на WM_GETMINMAXINFO программа может сообщить системе допустимые размеры окна, а результат обработки WM_MOUSEACTIVATE определяет, должна ли система активизировать окно. Разумеется, при асинхронной посылке отправитель не может получить достоверный ответ, поскольку не ждет окончания обработки.

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

Если посылается сообщение окну другой нити или другого процесса, то синхронное сообщение, как было описано выше, ставится в очередь «вне очереди» и посылается оконной функции, как только это становится возможным. Работа нити-отправителя блокируется до наступления одного из двух событий:

· выполнение вызванной оконной функции завершается;

· оконная функция вызывает функцию ReplyMessage (означающую примерно следующее: «Пусть я еще не все сделала, но с оставшейся работой справлюсь сама, не стойте над душой»).

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

Что касается оконных функций, выполняющих обработку синхронных сообщений, следует отметить действующие ограничения на вызовы системных функций. Запрещено (по крайней мере, до вызова ReplyMessage) вызывать любые функции, которые могут вызвать переключение системы на выполнение другой нити. К таким функциям относятся, в частности, GetMessage, PeekMessage, WaitMessage, Yield, Sleep, SleepEx, WaitForSingleObject, WaitForMultipleObjects, а также функции, вызывающие запуск либо завершение процесса или нити.

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

Синхронная посылка сообщений имеет один принципиальный недостаток. Корректная работа приложения, посылающего сообщение, зависит от корректности поведения оконной функции окна-приемника. Если эта функция, например, зацикливается, не успев вызвать ReplyMessage, то нить, пославшая сообщение, блокируется навечно не по своей вине. Чтобы избежать такой ситуации, Windows предлагает на выбор три решения.

Функция SendNotifyMessage представляет собой нечто среднее между синхронной и асинхронной посылкой. Посланные сообщения, как и для SendMessage, обрабатываются до сообщений из очереди, но нить-отправитель, как при PostMessage, не ожидает ответа.

Функция SendMessageTimeout аналогична SendMessage, однако ожидает ответа лишь в пределах указанного интервала времени.

Функция SendMessageCallback задает адрес функции, которая должна быть вызвана после окончания обработки посланного сообщения, при этом функция не ожидает немедленного ответа на сообщение.

2.2. Программа Spy++

Microsoft Spy++ – это программа, позволяющая получить в наглядном виде информацию о всех процессах в системе, нитях процессов (threads) и окнах, а также дающая возможность отслеживать поток сообщений. Spy++ входит в стандартную поставку пакета Microsoft Visual Studio.

Примерно такие же возможности, как Spy++, предоставляет программаWinSight32, поставляемая с продуктами фирмы Borland/Inprise. При желании можно использовать ее для выполнения лабораторной работы, однако ниже будет описана работа только с программой Spy++ версии 8.00.

Интерфейс Spy++ достаточно прост и понятен. Меню Spy позволяет открыть новое окно для просмотра потока сообщений (Log Messages), списка существующих окон (Windows), списка процессов (Processes) или нитей (Threads). В каждом окне можно выделить объект для дальнейшей работы. Можно также открыть несколько окон одного типа, например, для отслеживания сообщений, адресованных разным окнам. Mеню Window позволяет переключаться между открытыми окнами.

Для выполнения данной работы наиболее ценной возможностью является просмотр (протоколирование) сообщений. Имеется несколько способов настройки просмотра на нужные сообщения. При выполнении команды Spy+Log Messages открывается сначала диалог Message Options, позволяющий указать, для каких окон следует отслеживать сообщения, какие именно сообщения и куда записывать протокол. На закладке Windows пользователь может выбрать конкретное окно на экране, оттащив на него значок Finder Tool. Разумеется, для этого окно должно быть видимо. Можно также добавить отображение сообщений для родительского окна, для дочерних окон, для всех окон той же нити или того же процесса либо для всех окон в системе. На закладке Messages выбираются типы сообщений, которые нужно отслеживать. Можно включить или отключить целые группы сообщений (например, сообщения от клавиатуры или от командных кнопок) либо выбрать нужные сообщения из полного списка. На закладке Output пользователь может изменить формат и максимальное количество отображаемых сообщений.

Если окно выделено в списке окон и при этом является видимым, то можно найти его на экране с помощью команды контекстного меню Highlight. Граница окна будет мерцать в течение нескольких секунд.

Свойства выделенного объекта отображаются по команде View+Properties. Состав отображаемых свойств зависит от типа выбранного объекта.

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

Для нити отображаются имя модуля, идентификаторы процесса и нити, базовый приоритет процесса и текущий приоритет нити, текущее состояние нити, статистика затраченного времени. Можно перейти к отображению свойств процесса, щелкнув на его идентификаторе.

Для окна отображается большое количество информации о его размерах, заголовке, стилях, классе, родительском окне, первом из дочерних окон, «братских» окнах, окне-владельце, а также о процессе и нити, которым принадлежит окно.

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

Для каждого отслеженного сообщения программа показывает его тип, способ посылки и, если тип сообщения известен программе, содержательный смысл параметров wParam и lParam. Для неизвестных программе сообщений указываются только wParam и lParam, без расшифровки. Кроме того, для каждого сообщения указывается способ посылки: P – асинхронная посылка, S – синхронная посылка, R – ответ оконной функции на синхронную посылку. В ходе обработки одного синхронного сообщения могут посылаться и обрабатываться другие сообщения.

Меню Windows позволяет переключаться между ранее открытыми окнами. Меню Tree дает возможность изменять глубину вложения при отображении списков окон (показывать ли дочерние окна), процессов (показывать ли нити процесса) и нитей (показывать ли окна каждой нити).

Меню Message активно, только когда отображается поток сообщений. Команда Message+Logging Options дает возможность выбрать, для каких окон следует отслеживать сообщения, какие именно сообщения и куда записывать протокол. На закладке Windows пользователь может выбрать конкретное окно с помощью Finder Tool. (Другой способ выбрать окно – выделить его в списке окон и выполнить команду контекстного меню Messages.) Можно также добавить отображение сообщений для родительского окна, для дочерних окон, для всех окон той же нити или того же процесса либо для всех окон в системе. На закладке Messages выбираются типы сообщений, которые нужно отслеживать. Можно включить или отключить целые группы сообщений (например, сообщения от клавиатуры или от командных кнопок) либо выбрать нужные сообщения из полного списка. На закладке Output пользователь может изменить формат и максимальное количество отображаемых сообщений.

Команды Messages+Start Logging и Messages+Stop Logging включают и выключают протоколирование сообщений. Чтобы сделать это поскорее (и тем самым сократить число ненужных сообщений), можно воспользоваться значком в панели инструментов или клавишей F8. Команда Messages+Clear удаляет из окна все сообщения.

Для вывода копии протокола в файл можно использовать команду Messages+Save Log to File.

Команда контекстного меню Refresh обновляет содержимое текущего окна. Это может понадобиться, если состав отображаемых объектов изменился (например, были закрыты некоторые окна или открыты новые).

Наши рекомендации