迥异和诡异的SendMessage和PostMessage
1 故障现象
故障现象1:能够收到SendMessage()发出的消息,但收不到PostMessage()发出的消息。
故障现象2:能够收到PostMessage()发出的消息,但收不到SendMessage()发出的消息。
2 两个比喻
从发送端来说:
SendMessage()好比电信系统提供通话服务。
如果对方占线,立即返回。
如果对方不占线,就保持呼叫→接收端接听→通话→挂断。在挂断之前,发送端处于阻塞状态,不可以干别的事。
PostMessage()好比电子邮件系统提供电子邮件服务。
发送端把邮件交给电子邮件系统,然后立即返回,就可以干别的事了。
电子邮件系统将邮件放在队列缓存区中,缓慢地将邮件发送到接收端的邮箱里。
从接收端来说(!!! 关键 关键 关键 !!!):
要接收SendMessage()的消息,必须用手机接听,到邮箱里无法接收此类消息。
要接收PostMessage()的消息,必须到邮箱里接收,用手机无法接听此类消息。
1 技术原理
在本文中:
把SendMessage()发送的消息成为立即消息。
把PostMessage()发送的消息成为延迟消息。
在计算机系统里,立即消息和延迟消息分别使用完全不同的途径发送消息,必须采用相匹配的、完全不同的接收方法才能收到消息。
1.1 立即消息的收发
为了接收并处理立即消息,接收端应用程序必须准备一张(消息,处理函数)映射表,如下表所示:
消息 |
处理函数 |
WM_USER + 1 |
OnWmUser_1 |
WM_USER + 2 |
OnWmUser_2 |
… |
… |
WM_USER + n |
OnWmUser_n |
立即消息的发送与接收的协作流程如下表:
发送端应用程序 |
操作系统 |
接收端应用程序 (消息处理总入口函数) |
发送消息 |
||
阻塞发送端应用程序 |
||
调用接收端应用程序的消息处理总入口函数 |
||
在(消息,处理函数)映射表中搜索与消息相匹配的处理函数,立即调用处理函数。 |
||
向操作系统返回处理结果 |
||
向发送端应用程序返回处理结果 |
||
解除阻塞发送端应用程序 |
||
接收消息处理结果 |
||
继续其它事务 |
1.2 延迟消息的收发
延迟消息的发送与接收的协作流程如下表:
发送端应用程序 |
操作系统 |
接收端应用程序 |
发送消息 |
||
将消息放入接收端应用程序的消息队列中 |
||
继续其它事务 |
从消息队列中取出消息慢慢处理。 |
2 具体实现
以C++ Builder为例。
2.1 接收立即消息
要接收立即消息,也就是由SendMessage()发送的消息。
步骤1:声明并定义消息处理函数
步骤2:声明和定义(消息,处理函数)映射表
class TForm2 : public TForm { // 声明WM_COPYDATA 消息的处理函数 void __fastcall OnCopyData(const TMessage &msg); // 受理立即消息 --- 由 SendMessage() 发送的消息 // 声明和定义(消息,处理函数)映射表 BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_COPYDATA, TMessage, OnCopyData); END_MESSAGE_MAP(TForm) }; |
2.2 接收延迟消息
要接收延迟消息,也就是由PostMessage()发送的消息。
放置一个TApplicationEvents控件,该控件只能接收延迟消息,无法接收立即消息。
编写TApplicationEvents.OnMessage事件处理函数。如下表:
void __fastcall TForm2::AppEventsMessage(tagMSG &Msg, bool &Handled) { // 若收到延迟消息WM_USER_1 if (Msg.message == WM_USER_1) { // 此处编写消息处理代码 // 设立标志,消息已被处理 Handled = true; } else { // 设立标志,消息未被处理 Handled = false; } } |
3 结论
SendMessage()和PostMessage()的共性:
都能发送消息。
SendMessage和PostMessage的差异:
采用完全不同的途径发送消息,也要采用完全不同的方法和途径接收消息。
若接收途径与发送途径不匹配,就无法接收消息。
通过SendMessage()发送的消息,发送端发送并必须等待接收端处理,接收端立即处理并向发送端反馈处理结果,无延迟。
通过PostMessage()发送的消息,发送端发送后立即返回,不等待接收端不处理,接收端缓慢地延迟处理。
|
SendMessage |
PostMessage() |
发送端 |
直接发给接收端 要求接收端立即处理 在接收端处理完毕之前处于阻塞状态,不可以干别的事 可以立即获悉接收端的处理结果 |
消息经由OS缓存到接收端的消息队列里 发送完毕立即返回,可以干别的事 |
接收端 |
立即处理收到的消息 |
缓慢地从队列里取出消息并处理。 |
4 其它
SendMessage和PostMessage的其它特性,网上都有,本文不再重复与累述。
迥异和诡异的SendMessage和PostMessage的更多相关文章
- [转] - SendMessage、PostMessage原理
SendMessage.PostMessage原理 本文讲解SendMessage.PostMessage两个函数的实现原理,分为三个步骤进行讲解,分别适合初级.中级.高级程序员进行理解,三个步骤分别 ...
- SendMessage、PostMessage原理
SendMessage.PostMessage原理 本文讲解SendMessage.PostMessage两个函数的实现原理,分为三个步骤进行讲解,分别适合初级.中级.高级程序员进行理解,三个步骤分别 ...
- SendMessage和PostMessage区别以及WPARAM 和 LPARAM区别
WPARAM 和 LPARAM wParam和lParam 这两个是Win16系统遗留下来的产物,在Win16API中WndProc有两个参数:一个是WORD类型的16位整型变量:另一个是LONG类型 ...
- SENDMESSAGE和POSTMESSAGE
原文:http://www.cnblogs.com/wind-net/archive/2012/11/01/2750123.html SendMessage 和 PostMessage 的区别 1.首 ...
- 关于SendMessage和PostMessage的理解的例子
对于SendMessage 和 PostMessage 平时口头的解释是 SendMessage 发送消息后等待返回, PostMessage 发送消息后立即返回 . 但是这样解释还是不具体,什么叫等 ...
- sendmessage和postmessage的区别
BOOL PostMessage( HWND hWnd, // handle of destination window ...
- (转)深入解析SendMessage、PostMessage
转自:http://blog.csdn.net/xt_xiaotian/article/details/2778689 本文将使用C++语言,在MFC框架的配合下给出PostMessage.S ...
- SendMessage 和 PostMessage
1.首先是返回值意义的区别,我们先看一下 MSDN 里的声明: LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPar ...
- MFC的sendmessage和postmessage 以及sendmessagetimeout
PostMessage只负责将消息放到消息队列中,不确定何时及是否处理,相当于异步操作,执行后马上返回SendMessage要等到受到消息处理的返回码(DWord类型)后才继续,相当于同步操作,一直在 ...
随机推荐
- 对已经存在的hbase表修改压缩方式
业务上可能会遇到这种情况,在最初创建hbase表时候,未指定压缩方式,当数据导入之后,由rowkey带来的数据膨胀导致hdfs上的数据大小远远大于原始数据大小.所以这时候可能就不得不考虑使用压缩,但是 ...
- web 前端开发学习路线
初级 HTML 5 HTML 5 与 HTML 4 的区别 HTML 5 新增的主体结构元素 HTML 5 新增的非主体结构元素 HTML 5 表单新增元素与属性 HTML 5 表单新增元素与属性(续 ...
- ajax前台数据到后台
var username = $("#id").val(); var user={"userAccount":username,"userPasswo ...
- AVL-平衡二叉树的原理和实现
一.简介 本文将通过图解和代码详细讲解AVL平衡二叉树的性质及失衡和再平衡的内容.在看本文之前希望大家具备二分搜索树的相关知识.或移步<二分搜索树>了解二分搜索树. 二.平衡二叉树 前面关 ...
- 最近学习了JDK SPI
JDK SPI是什么 最近工作中听几个同事说了好几次SPI这个名词,虽然和我没关系,但是心里默默想还是学习一下,不然下次和我说到SPI,连是什么都不知道那就尴尬了. 所以SPI是什么呢?SPI全称Se ...
- Nginx入门(二):镜像和容器
0.docker常用命令 #镜像名 版本标签 镜像id 创建时间 镜像大小 REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289 ...
- Java8 日期 API 业务使用
最近在做账单结算业务,需要根据客户选择的结算方式来推算下一次结算日期以及该次结算日期段. 推算日期这样的业务直男君以前就写过,只不过使用的是熟悉的 java.util.date 和 java.util ...
- Netty源码分析 (三)----- 服务端启动源码分析
本文接着前两篇文章来讲,主要讲服务端类剩下的部分,我们还是来先看看服务端的代码 /** * Created by chenhao on 2019/9/4. */ public final class ...
- GNU大型项目构建和覆盖率生成(第一篇)
目录 0. 序言 1. 项目描述 2. 项目构建 2.1 编译规则 2.2 构建过程 3. 覆盖率分析 0. 序言 在开始正文之前,请允许我先说明一下本文的目的和写作的动机,好让读者不惑. 我们知道, ...
- 基于单细胞测序数据构建细胞状态转换轨迹(cell trajectory)方法总结
细胞状态转换轨迹构建示意图(Trapnell et al. Nature Biotechnology, 2014) 在各种生物系统中,细胞都会展现出一系列的不同状态(如基因表达的动态变化等),这些状态 ...