Поделиться через


Сведения о сообщениях и очередях сообщений

В отличие от приложений на основе MS-DOS, приложения на основе Windows управляются событиями. Они не выполняют явные вызовы функций (например, вызовы библиотеки времени выполнения C) для получения входных данных. Вместо этого они ждут, пока система передаст им входные данные.

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

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

В этом разделе рассматриваются следующие темы:

Сообщения Windows

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

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

Идентификатор сообщения — это именованной константой, которая определяет назначение сообщения. Когда процедура окна получает сообщение, она использует идентификатор сообщения для определения способа обработки сообщения. Например, идентификатор сообщения WM_PAINT сообщает процедуре окна, что клиентская область окна изменилась и должна быть перерисовывается.

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

Типы сообщений

В этом разделе описываются два типа сообщений:

Сообщения System-Defined

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

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

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

Prefix Категория сообщения Документация
ABM и ABN Панель инструментов рабочего стола приложения Сообщения и уведомления оболочки
ACM и ACN Элемент управления "Анимация" Сообщения элемента управления анимацией и уведомления элемента управления анимацией
BCM, BCN, BM и BN Button - элемент управления Сообщения элемента управления кнопками и уведомления элемента управления кнопками
CB и CBN ComboBox - элемент управления Сообщения элемента управления ComboBox и уведомления элемента управления ComboBox
CBEM и CBEN Элемент управления ComboBoxEx Сообщения ComboBoxEx и уведомления ComboBoxEx
СКК Общий элемент управления Управляющие сообщения
CDM Общее диалоговое окно Распространенные сообщения диалогового окна
DFM Контекстное меню по умолчанию Сообщения и уведомления оболочки
DL Перетащите список Перетаскивание уведомлений со списком
DM Элемент управления "Кнопка" по умолчанию Сообщения диалогового окна
DTM и DTN Элемент управления "Выбор даты и времени" Сообщения средства выбора даты и времени и уведомления о выборе даты и времени
EM и EN Элемент управления "Поле ввода" Изменение сообщений элемента управления, изменение уведомлений элемента управления, сообщения с расширенными возможностями и уведомления о расширенном редактировании
HDM и HDN Элемент управления "Заголовок" Сообщения элемента управления заголовком и уведомления элемента управления заголовком
HKM Элемент управления "Горячая клавиша" Сообщения элемента управления "Горячий ключ"
IPM и IPN контроль IP-адресов Сообщения IP-адресов и уведомления об IP-адресах
LB и LBN Элемент управления "Список" Сообщения со списком и уведомления со списком
LM Элемент управления SysLink Сообщения элемента управления SysLink
LVM и LVN Элемент управления "Представление списка" Сообщения представления списка и уведомления представления списка
MCM и MCN Элемент управления "Календарь на месяц" Сообщения в календаре за месяц и уведомления календаря за месяц
Управление на основе политик (PBM) Индикатор выполнения Сообщения индикатора выполнения
PGM и PGN Элемент управления "Пейджер" Сообщения элемента управления Pager и уведомления элемента управления Pager
PSM и PSN Страница свойств. Сообщения на странице свойств и уведомления на листе свойств
RB и RBN Элемент управления "Перекладка" Сообщения элемента управления иуведомления элемента управления rebar
SB и SBN Окно строки состояния Сообщения в строке состояния и уведомления в строке состояния
SBM Элемент управления "Полоса прокрутки" Сообщения полосы прокрутки
SMC Меню оболочки Сообщения и уведомления оболочки
STM и STN Статический элемент управления Статические сообщения элемента управления и уведомления статического элемента управления
ТБ и TBN Панель инструментов Сообщения элемента управления панелью инструментов и уведомления элемента управления панели инструментов
TBM и TRBN Элемент управления trackbar Сообщения элемента управления Trackbar и уведомления элемента управления Trackbar
TCM и TCN Элемент управления табуляции Сообщения элемента управления вкладками и уведомления элемента управления вкладками
TDM и TDN Диалоговое окно задачи Сообщения диалогового окна задачи и уведомления о диалоговых окнах задач
TTM и TTN Элемент управления "Подсказка" Сообщения элемента управления подсказками и уведомления элемента управления подсказками
TVM и TVN Элемент управления "Древовидное представление" Сообщения в виде дерева и уведомления в виде дерева
UDM и UDN Элемент управления "Вверх-вниз" Сообщения вверх-вниз и уведомления вверх-вниз
WM Общие сведения
Сообщения буфера обмена
Уведомления буфера обмена
Распространенные уведомления диалогового окна
Уведомления курсора
Сообщение о копировании данных
Сообщения диспетчера окон рабочего стола
Сообщения Управление устройствами
Уведомления диалогового окна
Динамические сообщения обмена данными
Уведомления о динамическом обмене данными
Уведомления перехватчика
Сообщения ускорителя клавиатуры
Уведомления ускорителя клавиатуры
Ввод сообщений с клавиатуры
Уведомления о вводе с клавиатуры
Уведомления меню
Уведомления о вводе с помощью мыши
Сообщения из нескольких интерфейсов документов
Необработанные входные уведомления
Уведомления полосы прокрутки
Уведомления таймера
Сообщения окна
Уведомления о окне

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

Сообщения Application-Defined

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

Значения идентификатора сообщения используются следующим образом:

  • Система резервирует значения идентификаторов сообщений в диапазоне 0x0000 до 0x03FF (значение WM_USER –1) для системных сообщений. Приложения не могут использовать эти значения для личных сообщений.
  • Значения в диапазоне 0x0400 (значение WM_USER) по 0x7FFF доступны для идентификаторов сообщений для частных классов окон.
  • Если приложение помечено версией 4.0, можно использовать значения идентификатора сообщения в диапазоне 0x8000 (WM_APP) через 0xBFFF для личных сообщений.
  • Система возвращает идентификатор сообщения в диапазоне 0xC000 по 0xFFFF, когда приложение вызывает функцию RegisterWindowMessage для регистрации сообщения. Идентификатор сообщения, возвращаемый этой функцией, гарантированно будет уникальным в системе. Использование этой функции предотвращает конфликты, которые могут возникнуть, если другие приложения используют один и тот же идентификатор сообщения для различных целей.

Маршрутизация сообщений

Система использует два метода для маршрутизации сообщений в процедуру окна: отправка сообщений в очередь первого входа, которая называется очередью сообщений, определенный системой объект памяти, в котором временно хранятся сообщения, и отправка сообщений непосредственно в процедуру окна.

Сообщение, отправленное в очередь сообщений, называется сообщением в очереди. В основном это результат ввода пользователем с помощью мыши или клавиатуры, например WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN и WM_CHAR сообщений. К другим сообщениям в очереди относятся сообщения таймера, рисования и выхода: WM_TIMER, WM_PAINT и WM_QUIT. Большинство других сообщений, которые отправляются непосредственно в процедуру окна, называются сообщениями без очереди.

Сообщения в очереди

Система может отображать любое количество окон за раз. Для маршрутизации ввода с помощью мыши и клавиатуры в соответствующее окно система использует очереди сообщений.

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

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

За исключением сообщения WM_PAINT , WM_TIMER и WM_QUIT сообщения система всегда публикует сообщения в конце очереди сообщений. Это гарантирует, что окно получает входные сообщения в правильной последовательности first in, first out (FIFO). Однако сообщение WM_PAINT , WM_TIMER и сообщение WM_QUIT хранятся в очереди и перенаправляются в процедуру окна, только если очередь не содержит других сообщений. Кроме того, несколько сообщений WM_PAINT для одного окна объединяются в одно WM_PAINT сообщение, консолидируя все недопустимые части клиентской области в одной области. Объединение WM_PAINT сообщений сокращает количество перерисовок содержимого клиентской области в окне.

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

Приложение может удалить сообщение из очереди с помощью функции GetMessage . Чтобы проверить сообщение, не удаляя его из очереди, приложение может использовать функцию PeekMessage . Эта функция заполняет MSG сведениями о сообщении.

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

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

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

Сообщения без очереди

Непереправляемые сообщения немедленно отправляются в процедуру окна назначения, минуя очередь системных сообщений и очередь сообщений потока. Система обычно отправляет сообщения без очереди, чтобы уведомлять окно о событиях, влияющих на нее. Например, когда пользователь активирует новое окно приложения, система отправляет окну ряд сообщений, включая WM_ACTIVATE, WM_SETFOCUS и WM_SETCURSOR. Эти сообщения уведомляют окно о том, что оно было активировано, что ввод с помощью клавиатуры направляется в окно и что курсор мыши был перемещен в пределах окна. Сообщения, не отправляемые в очередь, также могут возникать при вызове приложением определенных системных функций. Например, система отправляет сообщение WM_WINDOWPOSCHANGED после того, как приложение использует функцию SetWindowPos для перемещения окна.

Некоторые функции, которые отправляют сообщения без очереди, — BroadcastSystemMessage, BroadcastSystemMessageEx, SendMessage, SendMessageTimeout и SendNotifyMessage.

Обработка сообщений

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

Цикл сообщений

Простой цикл сообщений состоит из одного вызова каждой из трех функций: GetMessage, TranslateMessage и DispatchMessage. Обратите внимание, что при возникновении ошибки GetMessage возвращает –1, что приводит к необходимости специального тестирования.

MSG msg;
BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}

Функция GetMessage извлекает сообщение из очереди и копирует его в структуру типа MSG. Он возвращает ненулевое значение, если не встречается с сообщением WM_QUIT . В этом случае возвращается значение FALSE и завершается цикл. В однопотоковом приложении завершение цикла сообщений часто является первым шагом при закрытии приложения. Приложение может завершить свой собственный цикл с помощью функции PostQuitMessage, как правило, в ответ на сообщение WM_DESTROY в процедуре окна main приложения.

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

Цикл сообщений потока должен включать TranslateMessage , если поток должен получать ввод символов с клавиатуры. Система создает сообщения с виртуальным ключом (WM_KEYDOWN и WM_KEYUP) каждый раз, когда пользователь нажимает клавишу. Сообщение виртуального ключа содержит код виртуального ключа, который определяет, какая клавиша была нажата, но не ее значение символа. Чтобы получить это значение, цикл сообщений должен содержать TranslateMessage, который преобразует сообщение виртуального ключа в символьное сообщение (WM_CHAR) и помещает его обратно в очередь сообщений приложения. Символьное сообщение затем можно удалить при последующей итерации цикла сообщений и отправить в процедуру окна.

Функция DispatchMessage отправляет сообщение в процедуру окна, связанную с дескриптором окна, указанным в структуре MSG . Если дескриптор окна HWND_TOPMOST, DispatchMessage отправляет сообщение в процедуры окон всех окон верхнего уровня в системе. Если дескриптор окна имеет значение NULL, DispatchMessage ничего не делает с сообщением.

Поток main приложения запускает цикл сообщений после инициализации приложения и создания по крайней мере одного окна. После запуска цикл сообщений продолжает получать сообщения из очереди сообщений потока и отправлять их в соответствующие окна. Цикл сообщений завершается, когда функция GetMessage удаляет WM_QUIT сообщение из очереди сообщений.

Для очереди сообщений требуется только один цикл сообщений, даже если приложение содержит много окон. DispatchMessage всегда отправляет сообщение в соответствующее окно; Это связано с тем, что каждое сообщение в очереди является структурой MSG , содержащей дескриптор окна, которому принадлежит сообщение.

Цикл сообщений можно изменить различными способами. Например, можно получить сообщения из очереди, не отправляя их в окно. Это полезно для приложений, которые публикуют сообщения, не указывающие окно. Вы также можете направить GetMessage на поиск определенных сообщений, оставив другие сообщения в очереди. Это полезно, если необходимо временно обойти обычный порядок FIFO очереди сообщений.

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

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

Процедура окна

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

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

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

Так как процедура окна совместно используется всеми окнами, принадлежащими одному классу, она может обрабатывать сообщения для нескольких разных окон. Чтобы определить конкретное окно, на которое влияет сообщение, процедура окна может проверить дескриптор окна, переданный вместе с сообщением. Дополнительные сведения о процедурах окна см. в разделе Процедуры окна.

Фильтрация сообщений

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

Константы WM_KEYFIRST и WM_KEYLAST можно использовать в качестве значений фильтра для получения всех сообщений клавиатуры; Для получения всех сообщений мыши можно использовать константы WM_MOUSEFIRST и WM_MOUSELAST .

Любое приложение, которое фильтрует сообщения, должно гарантировать, что сообщение, удовлетворяющее фильтру сообщений, может быть опубликовано. Например, если приложение фильтрует WM_CHAR сообщение в окне, которое не получает ввод с клавиатуры, функция GetMessage не возвращает. Это фактически "зависает" приложение.

Публикация и отправка сообщений

Любое приложение может публиковать и отправлять сообщения. Как и в системе, приложение отправляет сообщение, копируя его в очередь сообщений, и отправляет сообщение, передавая данные сообщения в качестве аргументов в процедуру окна. Для публикации сообщений приложение использует функцию PostMessage . Приложение может отправлять сообщение, вызывая функцию SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage или SendDlgItemMessage .

Публикация сообщений

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

Приложение может публиковать сообщение без указания окна. Если приложение предоставляет дескриптор окна NULL при вызове PostMessage, сообщение отправляется в очередь, связанную с текущим потоком. Так как дескриптор окна не указан, приложение должно обработать сообщение в цикле сообщений. Это один из способов создания сообщения, которое применяется ко всему приложению, а не к определенному окну.

Иногда может потребоваться опубликовать сообщение во всех окнах верхнего уровня в системе. Приложение может публиковать сообщение во все окна верхнего уровня, вызвав PostMessage и указав HWND_TOPMOST в параметре hwnd .

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

отправка сообщений

Приложение обычно отправляет сообщение для уведомления процедуры окна о немедленном выполнении задачи. Функция SendMessage отправляет сообщение в процедуру окна, соответствующую заданному окну. Функция ожидает завершения обработки процедуры окна, а затем возвращает результат сообщения. Родительское и дочернее окна часто обмениваются сообщениями, отправляя сообщения друг другу. Например, родительское окно с элементом управления "Редактирование" в качестве дочернего окна может задавать текст элемента управления, отправляя ему сообщение. Элемент управления может уведомлять родительское окно об изменениях в тексте, выполненных пользователем, отправляя сообщения обратно родительскому окну.

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

Иногда может потребоваться отправить сообщение во все окна верхнего уровня в системе. Например, если приложение изменяет системное время, оно должно уведомить все окна верхнего уровня об изменении, отправив WM_TIMECHANGE сообщение. Приложение может отправить сообщение во все окна верхнего уровня, вызвав SendMessage и указав HWND_TOPMOST в параметре hwnd . Вы также можете транслировать сообщение во все приложения, вызвав функцию BroadcastSystemMessage и указав BSM_APPLICATIONS в параметре lpdwRecipients .

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

Взаимоблокировки сообщений

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

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

Чтобы избежать потенциальных взаимоблокировок в приложении, рассмотрите возможность использования функций SendNotifyMessage или SendMessageTimeout . В противном случае оконная процедура может определить, было ли полученное сообщение отправлено другим потоком путем вызова функции InSendMessage или InSendMessageEx . Перед вызовом любой из функций из предыдущего списка при обработке сообщения процедура окна должна сначала вызвать InSendMessage или InSendMessageEx. Если эта функция возвращает значение TRUE, оконная процедура должна вызвать функцию ReplyMessage перед любой функцией, которая вызывает поток для получения управления.

Трансляция сообщений

Каждое сообщение состоит из идентификатора сообщения и двух параметров: wParam и lParam. Идентификатор сообщения — это уникальное значение, указывающее назначение сообщения. Параметры предоставляют дополнительные сведения, относящиеся к конкретному сообщению, но параметр wParam обычно является значением типа, предоставляющим дополнительные сведения о сообщении.

Широковещательная рассылка — это просто отправка сообщения нескольким получателям в системе. Чтобы транслировать сообщение из приложения, используйте функцию BroadcastSystemMessage , указав получателей сообщения. Вместо указания отдельных получателей необходимо указать один или несколько типов получателей. Это приложения, устанавливаемые драйверы, сетевые драйверы и драйверы устройств на уровне системы. Система отправляет широковещательные сообщения всем членам каждого указанного типа.

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

Система передает сообщения получателям в следующем порядке: драйверы устройств системного уровня, сетевые драйверы, устанавливаемые драйверы и приложения. Это означает, что драйверы устройств системного уровня, если они выбраны в качестве получателей, всегда получают первую возможность ответить на сообщение. В заданном типе получателя ни один драйвер не будет гарантированно получать заданное сообщение перед любым другим драйвером. Это означает, что сообщение, предназначенное для конкретного драйвера, должно иметь глобальный уникальный идентификатор сообщения, чтобы его не обрабатывал ни один другой драйвер.

Вы также можете транслировать сообщения во все окна верхнего уровня, указав HWND_BROADCAST в функции SendMessage, SendMessageCallback, SendMessageTimeout или SendNotifyMessage .

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

Примечание

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

Запросы сообщений

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

Чтобы опросить у получателей разрешение на выполнение заданного действия, используйте сообщение запроса. Вы можете создавать собственные сообщения запросов, задав значение BSF_QUERY в параметре dwFlags при вызове BroadcastSystemMessage. Каждый получатель сообщения запроса должен возвращать значение TRUE , чтобы функция отправляла сообщение следующему получателю. Если какой-либо получатель возвращает BROADCAST_QUERY_DENY, трансляция немедленно завершается, а функция возвращает ноль.