windows 如何从不同的线程执行 SendMessage?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2942841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 14:33:06  来源:igfitidea点击:

How is executed a SendMessage from a different thread?

windowswinapi

提问by lornova

When we send a message, "if the specified window was created by the calling thread, the window procedure is called immediately as a subroutine". But "if the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code." (taken from MSDN documentation for SendMessage).

当我们发送消息时,“如果指定的窗口是由调用线程创建的,则窗口过程将立即作为子例程被调用”。但是“如果指定的窗口是由不同的线程创建的,系统将切换到该线程并调用适当的窗口过程。线程之间发送的消息仅在接收线程执行消息检索代码时才被处理。”(取自 MSDN 文档SendMessage) .

Now, I don't understand how(or, more appropriately, when) the target windows procedure is called. Of course the target thread will not be preempted (the program counter is not changed). I presume that the call will happen during some wait function (like GetMessageor PeekMessage), it is true? That process is documented in detail somewhere?

现在,我不明白如何(或更恰当地说,何时)目标 Windows 过程被调用。当然目标线程不会被抢占(程序计数器不变)。我认为调用会在某些等待函数(如GetMessagePeekMessage)期间发生,这是真的吗?该过程在某处有详细记录吗?



Update:the rationale behind it is explained by the QS_SENDMESSAGEflag of GetQueueStatus()and MsgWaitForMultipleObjects():

更新:其背后的基本原理由and的QS_SENDMESSAGE标志解释:GetQueueStatus()MsgWaitForMultipleObjects()

QS_SENDMESSAGE
 A message sent by another thread or application is in the queue.

This, along with additional remarks in MSDN documentation, means that a message sent by another thread is actually posted to the queue. Then, as soon as GetMessageor PeekMessageare called, it will be processed before any other posted message by being sent directly to the window procedure.

这与 MSDN 文档中的附加说明一起意味着另一个线程发送的消息实际上已发布到队列中。然后,一旦GetMessagePeekMessage被调用,它将在任何其他发布的消息之前通过直接发送到窗口过程来处理。

采纳答案by Viktor Svub

I see some confusion here.

我看到这里有些混乱。

According to the MSDN docs, when you touch the message queue of the current thread with the intent of message processing (e.g. if you call PeekMessageor GetMessage), allpending sent (i.e. non-queued) messages from other threads are handled - passed to the WndProc- and then the message queue is checked, so:

根据 MSDN 文档,当您出于消息处理的意图接触当前线程的消息队列时(例如,如果您调用PeekMessageGetMessage),则处理来自其他线程的所有待发送(即非排队)消息 - 传递给WndProc-然后检查消息队列,所以:

  • sent messages nevergo through DispatchMessageand are handled as soon as possible:
    • in the current thread, they are simply passed to WndProc
    • in another thread, they are handled before anyposted message processing
  • to be able to handle sent messages, the target thread still needs a message pump
  • PostThreadMessagedoes just what it states - postsa message in a threads queue - such messages are not directed to any window and must be handled explixitly
  • the onlymessages handled by DispatchMessageare those created by PostMessageor some system facility (timers, events, user input, etc.)
  • to avoid deadlocks, use SendNotifyMessage, SendMessageTimeoutor SendMessageCallbackinstead of plain SendMessagebetween different threads
  • 发送的消息永远不会通过DispatchMessage并尽快处理:
    • 在当前线程中,它们被简单地传递给 WndProc
    • 在另一个线程中,它们在任何发布的消息处理之前被处理
  • 为了能够处理发送的消息,目标线程仍然需要一个消息泵
  • PostThreadMessage做它所说的 -在线程队列中发布消息 - 此类消息不会定向到任何窗口,必须明确处理
  • 通过处理的消息DispatchMessage是那些由创建PostMessage或一些系统设施(定时器,事件,用户输入等)
  • 使用,以避免死锁,SendNotifyMessageSendMessageTimeoutSendMessageCallback而不是纯SendMessage不同线程之间

For further reference, study the Remarks section of the MSDN PeekMessageentry.

如需进一步参考,请研究 MSDNPeekMessage条目的备注部分。

回答by selbie

Short answer: When the target thread calls GetMessage (or PeekMessage) followed by DispatchMessage, then the SendMessage from the other thread is received and handled.

简短回答:当目标线程调用 GetMessage(或 PeekMessage)后跟 DispatchMessage 时,来自另一个线程的 SendMessage 将被接收和处理。

I am not certain if the received SendMessage preempts other messages in the queue or not. Either way, a SendMessage from one thread to another is like saying: "Post this message to the other thread's message queue. Return when that thread has finished processing it".

我不确定收到的 SendMessage 是否抢占队列中的其他消息。无论哪种方式,从一个线程到另一个线程的 SendMessage 就像说:“将此消息发布到另一个线程的消息队列。当该线程完成处理后返回”。

An now for an answer you didn't ask for:

现在为你没有要求的答案:

In general, when I program interactions between the main UI thread and a worker thread, I try to avoid using SendMessage. If you aren't careful, you can get into a situation where both threads are deadlocked on each other. (Think of the case where the main thread is calling WaitForSingleObject to wait for the worker thread to complete, but the worker thread is blocked on SendMessage back to the UI thread).

通常,当我对主 UI 线程和工作线程之间的交互进行编程时,我会尽量避免使用 SendMessage。如果您不小心,您可能会遇到两个线程相互死锁的情况。(想想主线程正在调用WaitForSingleObject 等待工作线程完成的情况,但工作线程在SendMessage 返回UI 线程时被阻塞)。

回答by Oleg

Every windows is associated with a thread. You can use GetWindowThreadProcessIdto retrieves the thread of every window. If you send a message to a windows from the other thread with respect of PostThreadMessagethe message will be placed in the thread's message queue. The thread must have a get-message loop (with GetMessagefor example) to get the messages and dispatch there to the window procedure of the window.

每个窗口都与一个线程相关联。您可以使用GetWindowThreadProcessId来检索每个窗口的线程。如果从另一个线程向一个窗口发送消息,则PostThreadMessage该消息将被放置在该线程的消息队列中。线程必须有一个获取消息循环(GetMessage例如)来获取消息并在那里分派到窗口的窗口过程。

It you call SendMessageinstead of PostThreadMessageyou call the Windows Procedure directly without placing it in the message queue. Some nonqueued messages are sent also immediately to the destination window procedure, bypassing the system message queue and thread message queue. (see http://msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#nonqueued_messages). The main reason to use SendMessageinstead of PostThreadMessageif you want to give some information from another windows (control) like read a text from an another control during processing of another message. You should do this only if it really needed. So if you use SendMessageto send a message to a windows from another thread your current thread must be blocked for some time.

您调用它SendMessage而不是PostThreadMessage直接调用 Windows 过程而不将其放入消息队列中。一些未排队的消息也会立即发送到目标窗口过程,绕过系统消息队列和线程消息队列。(参见http://msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#nonqueued_messages)。 如果您想从另一个窗口(控件)提供一些信息,例如在处理另一条消息期间从另一个控件读取文本SendMessagePostThreadMessage则使用而不是的主要原因。只有在确实需要时才应该这样做。因此,如果您使用SendMessage从另一个线程向窗口发送消息,则您当前的线程必须被阻塞一段时间。

It can be a good idea to use PostThreadMessageor SendMessageCallbackinstead of SendMessageif it is possible.

如果可能的话,使用PostThreadMessageSendMessageCallback代替它可能是一个好主意SendMessage