Когда мы отправляем сообщение, "если указанное окно было создано вызывающим потоком, оконную процедуру сразу называют как подпрограмма". Но, "если указанное окно было создано другим потоком, система переключается на тот поток и называет соответствующую оконную процедуру. Сообщения, отправленные между потоками, обрабатываются только, когда поток получения выполняет код извлечения сообщений". (взятый из документации MSDN для SendMessage
).
Теперь, я не понимаю, как (или, более соответственно, когда) целевую процедуру окон называют. Конечно, целевой поток не будет вытеснен (счетчик команд не изменяется). Я предполагаю, что вызов произойдет во время некоторых, ожидают функция (как GetMessage
или PeekMessage
), это верно? Тот процесс документируется подробно где-нибудь?
Обновление: объяснение позади него объяснено QS_SENDMESSAGE
флаг GetQueueStatus()
и MsgWaitForMultipleObjects()
:
QS_SENDMESSAGE
A message sent by another thread or application is in the queue.
Это, наряду с дополнительными комментариями в документации MSDN, означает, что сообщение, отправленное другим потоком, на самом деле добавлено очереди. Затем как только GetMessage
или PeekMessage
названы, это будет обработано перед любым другим добавленным сообщением, будучи отправленным непосредственно в оконную процедуру.
Я вижу здесь некоторую путаницу.
Согласно документации MSDN, когда вы касаетесь очереди сообщений текущего потока с целью обработки сообщения (например, если вы вызываете PeekMessage
или GetMessage
), все ожидающие отправленные (т.е. не поставленные в очередь) сообщения из других потоков обрабатываются - передаются в WndProc
- а затем проверяется очередь сообщений, поэтому:
DispatchMessage
и обрабатываются при первой возможности:
WndProc
PostThreadMessage
делает именно то, что заявляет - отправляет сообщение в очередь потоков - такие сообщения не направляются ни в какое окно и должны обрабатываться явно DispatchMessage
, создаются PostMessage
или некоторыми системными средствами (таймеры, события, ввод данных пользователем и т. д.) SendNotifyMessage
, SendMessageTimeout
или SendMessageCallback
вместо обычного SendMessage
между разными потоками . запись MSDN PeekMessage
.
Каждое окно связано с потоком. Вы можете использовать GetWindowThreadProcessId
для получения потока каждого окна. Если вы посылаете сообщение окну из другого потока с помощью PostThreadMessage
, сообщение будет помещено в очередь сообщений потока. Поток должен иметь цикл get-message (например, с GetMessage
), чтобы получать сообщения и отправлять их в оконную процедуру окна.
Если вы вызываете SendMessage
вместо PostThreadMessage
, вы вызываете процедуру окна напрямую, не помещая ее в очередь сообщений. Некоторые сообщения, не занесенные в очередь, также сразу отправляются в целевую оконную процедуру, минуя системную очередь сообщений и очередь сообщений потока. (см. http://msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#nonqueued_messages). Основная причина использовать SendMessage
вместо PostThreadMessage
, если вы хотите передать некоторую информацию из другого окна (элемента управления), например, прочитать текст из другого элемента управления во время обработки другого сообщения. Вы должны делать это только в том случае, если это действительно необходимо. Так, если вы используете SendMessage
для отправки сообщения окну из другого потока, ваш текущий поток должен быть заблокирован на некоторое время.
Может быть хорошей идеей использовать PostThreadMessage
или SendMessageCallback
вместо SendMessage
, если это возможно.
Короткий ответ: Когда целевой поток вызывает GetMessage (или PeekMessage), за которым следует DispatchMessage, то SendMessage от другого потока принимается и обрабатывается.
Я не уверен, вытесняет ли полученное SendMessage другие сообщения в очереди или нет. В любом случае, SendMessage от одного потока к другому - это все равно, что сказать: "Помести это сообщение в очередь сообщений другого потока. Вернись, когда этот поток закончит его обработку".
А теперь ответ, о котором вы не спрашивали:
Вообще, когда я программирую взаимодействие между основным потоком пользовательского интерфейса и рабочим потоком, я стараюсь избегать использования SendMessage. Если вы не будете осторожны, вы можете попасть в ситуацию, когда оба потока заблокируют друг друга. (Вспомните случай, когда основной поток вызывает WaitForSingleObject, чтобы дождаться завершения рабочего потока, но рабочий поток заблокирован на SendMessage обратно в поток UI).