SendMessage哪些事儿

关于SendMessage和PostMessage

https://docs.microsoft.com/en-us/windows/win32/winmsg/using-messages-and-message-queues#posting-a-message

简单的理解,PostMessage把消息放到接收消息线程的消息队列(post-queue)中,并且该函数还设置QS_POSTMESSAGE标志唤醒位,调用该函数的线程不等待其执行。SendMessage分两种情况:(1)发送消息的线程与接收消息的线程是同一个线程:直接调用指定窗口的窗口过程函数,等待其返回。       

(2)发送消息的线程与接收消息的线程是不同线程(包括同一进程的不同线程):①消息首先被追加到接收线程的发送消息队列(send-queue),同时接收线程的QS_SENDMESSAGE被设置,接收线程如果有正在执行的代码并且没有等待消息(GetMessage,PeekMessage,WaitMessage),发送的消息不会被处理;②只有当接收线程等待消息时,系统首先检查QS_SENDMESSAGE是否被设置,如果是,从发送消息队列中取出第一个消息交给对应窗口的过程函数处理;③接收线程处理消息时,发送线程被系统置为空闲状态(idle),等待一个消息出现在其应答消息队列(req-queue)中,因为该线程是空闲状态,所以该线程可以处理其他任务;④接收线程调用窗口过程后的返回值被登记到发送线程的应答消息队列中,这时发送线程被唤醒,取出应答消息队列中的返回值,即SendMessage的返回值;⑤当接收线程的发送消息队列为空时,QS_SENDMESSAGE的标记被关闭。当一个线程等待SendMessage返回时,其基本处于空闲状态(idle),可以执行一个任务,如果有线程给该线程建立的窗口发消息,其窗口过程可以立即执行,这种情况下,系统不必等待线程去调用GetMessage、PeekMessage或WaitMessage。【详情可见《windows核心编程》】

第(2)种情况下,接收消息的线程可以调用InMessage判断该消息由其他线程发送,进而执行ReplyMessage,调用该函数允许发送消息的线程继续执行,就像接收消息的线程处理完消息,返回控制权一样。https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-replymessage?redirectedfrom=MSDN

可以使用GetQueueStatus查询消息队列的状态,具体参考https://blog.csdn.net/zhangyq73/article/details/1658086

从线程的队列中提取消息的算法:当一个线程调用GetMessage或PeekMessage时,系统必须检查线程的队列状态标志的情况,并确定应该处理哪个消息。
1) 如果QS_SENDMESSAGE标志被设置,系统向相应的窗口过程发送消息。GetMessage或PeekMessage函数在内部进行这种处理,并且在窗口过程处理完消息之后不返回到线程,这些函数要等待其他要处理的消息。
2) 如果消息在线程的登记消息队列中,函数GetMessage或PeekMessage填充传递给它们的MSG结构,然后函数返回。这时,线程的消息循环通常调用DispatchMessage,让相应的窗口过程来处理消息。
3) 如果QS_QUIT标志被设置。GetMessage或PeekMessage返回一个WM_QUIT消息(其中wParam参数是规定的退出代码)并复位QS_QUIT标志。
4) 如果消息在线程的虚拟输入队列,函数GetMessage或PeekMessage返回硬件输入消息。
5) 如果QS_PAINT标志被设置,GetMessage或PeekMessage为相应的窗口返回一个WM_AINT消息。
6) 如果QS_TIMER标志被设置,GetMessage或PeekMessage返回一个WM_TIMER消息。

关于PostMessage和PostThreadMessage

均可以在不同线程间发送队列消息,但消息的接收者标识码不同,PostMessage使用窗口句柄,PostThreadMessage使用线程标识码。前者发送给UI线程;后者既可以发送消息给UI线程,也可以发送给工作线程,如果线程没有消息队列则返回失败。线程可以通过调用PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE)来强制系统创建消息队列,再调用GetMesssge或PeekMesssge来取得消息。PostMessage窗口句柄设置NULL时,相当于PostThreadMessage使用GetCurrentThreadId作为线程id参数。

关于SendMessageCallback和SendNotifyMessage

SendMessage给指定窗口(一个或多个窗口)发送消息,会等待窗口过程处理完消息后才返回, 如果要立即返回,可以使用SendMessageCallback或者SendNotifyMessage。SendMessageCallback:如果目标窗口跟调用者在同一线程,效果同SendMessage;如果不在同一线程,目标窗口的窗口过程处理消息后,系统会调用该函数指定的回调函数,并把返回值及参数传递给回调函数。SendNotifyMessage:如果目标窗口由调用者线程创建,则调用其窗口过程并等待其返回;如果目标窗口由其他窗口创建,SendNotifyMessage将消息传递到目标窗口的窗口过程,并立即返回(MSDN)。从找到的资料来看,消息是发送到一个可自扩充的队列(链式队列)中,不会像PostMessage那样丢失消息(PostMessage有消息队列大小限制,可能丢失消息)。

关于SendMessageTimeout

SendMessageTimeout 函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,并且,如果指定的窗口属于不同的线程,直到窗口程序处理完消息或指定的超时周期结束函数才返回。如果接收消息的窗口和当前线程属于同一个队列,窗口程序立即调用,超时值无用。

注:PostMessage, SendNotifyMessage, SendMessageCallback由于异步处理的原因,发送小于WM_USER的消息时,不能传递指针参数。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值