如何向在另一个线程创建的窗口发送SendMessage()消息?

9
我有一个情况,想要向在另一个线程上创建的窗口SendMessage。默认行为似乎是永远阻塞而且不起作用。所以我改变了调用方式PostMessage,这样不会阻塞发送线程,但消息似乎从未到达预期的窗口。那么我如何对在单独线程上创建的窗口进行SendMessage,或者这是不可能的?

前一段时间有一个类似的问题。它是关于C#的,但是它有点与语言无关。https://dev59.com/klfUa4cB1Zd3GeqPKK_L#6165532 - Skurmedel
4
投反对票的人,这是一个什么问题? - bobobobo
如果您发布一些代码,将会很有帮助:SendMessage/PostMessage 调用和消息处理程序。 - hamstergene
5个回答

2

PostThreadMessage函数将消息发布到指定线程的消息队列中。您可以指定要发布消息的线程标识符。这是您想要的吗?


2
目标窗口的线程在做什么呢?它需要通过消息循环来接收发送或发布到该窗口的消息。通常,这是通过使用GetMessage/TranslateMessage/DispatchMessage循环来实现的。如果线程正在执行其他操作(例如阻塞等待事件、互斥或IO完成,或者忙于某个计算循环),则不会接收消息:向该线程发送SendMessage将会被阻塞,而PostMessage将会被发布但无法传递。
如果目标线程既需要管理事件或类似事务,又拥有一个窗口,则可能需要在该线程的消息循环中使用MsgWaitForMultipleObjects。

1
每个创建的控件都属于创建它的线程,这意味着该控件的 WndProc 将在创建该控件的线程中运行。您可以使用 SendMessage 和 PostMessage 自由地向任何控件发送消息。

这是否意味着程序的所有GUI元素都必须在主线程上创建? - bobobobo
3
这是绝对不正确的:SendMessage 存在的原因之一是允许一个 GUI 线程与另一个 GUI 线程通信:它会执行一些协调线程间同步的工作。如果每个线程都适当地处理消息,那么拥有多个 GUI 线程的进程是完全合法的,每个线程都拥有窗口。话虽如此,更简单和适当的设计通常是一个单独的 GUI 线程,具有适当的非 GUI 工作者。 - BrendanMcK
这不是真的。您可以自由地向其他线程的窗口发送消息。 - hamstergene
@Brendan 但是窗口不是必须在它们所属的线程上创建吗?而且通常你想在一个线程上完成这个操作,对吧? - Seth Carnegie
3
根据定义,窗口“属于”创建它的线程:这意味着发送或发布到该窗口的任何消息都将由创建它的线程进行处理。但是,任何其他线程[1]可以自由地使用SendMessage或PostMessage向该窗口发送/发布消息(Windows会确保消息被路由/编排到HWND的创建者/所有者线程)。([1]假设线程在相同的桌面上,并具有适当的UIPI权限。) - BrendanMcK

1

你遇到了死锁问题。例如,如果你向另一个线程发送SendMessage消息,那么该线程中的windowProc会SendMessage回到你的窗口,它们将永远相互等待而被锁定。

你需要修复PostMessage(它确实传递消息,只是你的代码中有错误),或者非常小心地确定谁在何时调用谁。

为了防止繁忙或挂起的线程,可以使用SendMessageTimeout


0
CWnd::PostMessage和CWnd::SendMessage存在相同的问题。消息被推送出去,但没有被任何东西接收到。SendMessage是通过设计来阻塞的;它的工作是阻塞线程直到消息被接收。
MSDN关于SendMessage的说明如下:
“SendMessage函数调用指定窗口的窗口过程,并且在窗口过程处理完消息之前不返回。”
可以使用CWnd::PostThreadMessagewinapi PostMessage向另一个线程上的窗口发送消息。创建窗口时,可以使用GetSafeHwnd()获取句柄,或者在创建线程时使用线程ID。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接