[MFC] MFC消息机制的补充

之前写了[MFC] 消息映射机制的使用和原理浅析,还有些需要补充的,都记在这里。

MFC 消息的分类

MFC消息分为系统消息和自定义消息。
在这里插入图片描述
图片来源:C语言/C++教程 大型源码案例分析:MFC消息系统的代码解析 易道云编程

系统消息分为窗口消息、命令消息、通知消息。消息ID是0 ~ 1023。
每个窗口的自定义消息的消息ID需要从1024开始。声明方法为:

#define MY_MSG_1 (WM_USER + 1)

SendMessage

[MFC] 消息映射机制的使用和原理浅析中,用SendMessage发了一个消息。

void CMFCApplication1Dlg::OnBnClickedButton1()
{
	::SendMessage(this->GetSafeHwnd(),MY_MSG_1,NULL,NULL);	
}

SendMessage发出的消息是不经过消息循环的。
所以debug时可以看到,没有经过任何loop函数,直接就是AfxWndProc了,最终通过MessageMap找到对应的响应函数。
此时的函数堆栈调用:
在这里插入图片描述

未排队的消息
未排队的消息会立即发送到目标窗口过程,绕过系统消息队列和线程消息队列。 系统通常发送未排队的消息,以通知窗口影响它的事件。 例如,当用户激活新的应用程序窗口时,系统会向窗口发送一系列消息,包括 WM_ACTIVATE、 WM_SETFOCUS和 WM_SETCURSOR。 这些消息通知窗口已激活,键盘输入已定向到窗口,鼠标光标已在窗口边框内移动。 当应用程序调用某些系统函数时,也可能导致未排队的消息。 例如,在应用程序使用 SetWindowPos 函数移动窗口后,系统会发送WM_WINDOWPOSCHANGED消息。
发送非排队消息的一些函数包括 BroadcastSystemMessage、 BroadcastSystemMessageEx、 SendMessage、 SendMessageTimeout 和 SendNotifyMessage。
来源:Microsoft Learn 关于消息和消息队列

PostMessage 和 消息循环

把上面的SendMessage改成PostMessage试一下。

void CMFCApplication1Dlg::OnBnClickedButton1()
{
	::PostMessage(this->GetSafeHwnd(),MY_MSG_1,NULL,NULL);	
}

此时的函数堆栈调用:
在这里插入图片描述
可以看到调用堆栈不同。
在进入AfxWndProc之前,进入了RunModalLoop。
RunModalLoop就是CWnd的消息循环处理函数。

所以用SendMessage发出的消息,没有经过消息队列。
使用PostMessage发出的消息,会进入系统的消息队列,需要窗口的消息循环来处理。

线程可以使用 PostMessage 或 PostThreadMessage 函数将消息发布到其自己的消息队列或另一个线程的队列。
来源:Microsoft Learn 关于消息和消息队列

消息循环中,主要做了以下事情:
第一个循环:

// phase1: check to see if we can do idle work
while (bIdle &&
			!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
......

PeekMessage 消息,获取消息,而不在队列中删除消息。这里对PeekMessage的返回值进行了非判断,当取不到消息的时候,进行IDLE空闲判断和处理。

第二个循环:

// phase2: pump messages while available
do
{
	......
}while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));

这个循环也是PeekMessage获取消息,然后在循环体中,进行pump meessage(消息泵)

// pump message, but quit on WM_QUIT
if (!AfxPumpMessage())

AfxPumpMessage中,会GetMessage()、AfxPreTranslateMessage()、TranslateMessage()、DispatchMessage()。

系统为每个 GUI 线程维护一个系统消息队列和一个特定于线程的消息队列。
~
每当用户移动鼠标、单击鼠标按钮或键盘上的类型时,鼠标或键盘的设备驱动程序会将输入转换为消息,并将其置于系统消息队列中。 系统一次从系统消息队列中删除一个消息,检查它们以确定目标窗口,然后将其发布到创建目标窗口的线程的消息队列。 线程的消息队列接收线程创建的窗口的所有鼠标和键盘消息。 线程从其队列中删除消息,并指示系统将其发送到相应的窗口过程进行处理。
来源:Microsoft Learn 关于消息和消息队列

PreTranslateMessage和WindowProc

这里提一下PreTranslateMessage函数。
PreTranslateMessage是一个虚函数。它在TranslateMessage和DispatchMessage之前触发。当它返回true时,消息不会再发送给TranslateMessage和DispatchMessage。当它返回false时,消息会继续发送给TranslateMessage和DispatchMessage。

对于窗口类,可以重写自己的PreTranslateMessage()。这样可以捕获消息来进行一些自定义处理。
它只能捕获经过消息队列的消息,不经过消息队列的消息无法捕获。

WindowProc函数也是可以捕获消息,对消息进行自定义处理的。
PreTranslateMessage和WindowProc的区别在于:

  1. 只有经过消息队列的消息PreTranslateMessage才捕获的到。比如SendMessage发出的本窗口消息,不经过消息队列,PreTranslateMessage没反应,但是WindowProc捕获得到。
  2. 根据上面写的消息循环部分,可以知道,每个线程都有一个消息循环,它从线程的消息对列中获取消息,然后对消息进行TranslateMessage()、DispatchMessage(),DispatchMessage会把消息发送给对应的窗口。PreTranslateMessage就是重写的位于TranslateMessage之前的函数。WindowProc是窗口用于接收消息的函数。这个两个函数的调用位置是不同的。

1:
MFC中PreTranslateMessage是GetMessage(…)函数的下一级操作,即GetMessage(…)从消息队列中获取消息后,交由PreTranslateMessage()处理,若其返回FALSE则再交给TranslateMessage和DispatchMessage处理(进入WindowProc);
如果用SendMessage, 则消息直接交到WindowProc处理,所以GetMessage不会取得SendMessage的消息,当然PreTranslateMessage也就不会被调用。
如果用PostMessage,则消息进入消息队列,由GetMessage取得,PreTranslateMessage就有机会进行处理。
2:
SendMessage要区分环境,如果是对本线程的窗口SendMessage,则不经过任何消息循环,也不放入消息队列,直接调用WindowProc,所以GetMessage和PreTranslateMessage都捕获不到;如果SendMessage是向其它线程或其它进程的窗口发消息,则消息进入消息队列,GetMessage和PreTranslateMessage能捕获到这个消息。
原文:VC++ PreTranslateMessage和WindowProc的使用总结

原文链接:https://blog.csdn.net/libaineu2004/article/details/90600433

参考

C语言/C++教程 大型源码案例分析:MFC消息系统的代码解析 易道云编程

SendMessage() 发出的消息 PreTranslateMessage() 不一定能接收到!

Microsoft Learn 关于消息和消息队列

MFC学习(一):MFC的消息循环 --讲解到位

VC++ PreTranslateMessage和WindowProc的使用总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/371819.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaScript + CSS】随机生成十六进制颜色

效果图 实现 <template><div class"year_area"><div class"year_list"><el-row :span"24"><div :class"showAll"><el-col :span"5" v-for"(item, index) in defaulList" :key&…

【紧耦合新范式】Think-on-Graph:解决大模型在医疗、法律、金融等垂直领域的幻觉

Think-on-Graph&#xff1a;解决大模型在医疗、法律、金融等垂直领域的幻觉 Think-on-Graph 原理ToG 算法步骤&#xff1a;想想再查&#xff0c;查查再想实验结果 论文&#xff1a;https://arxiv.org/abs/2307.07697 代码&#xff1a;https://github.com/IDEA-FinAI/ToG Think…

开源节点框架STNodeEditor使用

节点&#xff0c;一般都为树形Tree结构&#xff0c;如TreeNode&#xff0c;XmlNode。 树形结构有其关键属性Parent【父节点】&#xff0c;Children【子节点】 LinkedListNode为链表线性结构&#xff0c;有其关键属性Next【下一个】&#xff0c;Previous【上一个】&#xff0c…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--强化学习、模仿学习、机器人

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起…

源码梳理(2)SpringMVC的执行流程及涉及到的相关组件

文章目录 1&#xff0c;Spring MVC核心组件DispatcherServlet1.1 DispatcherServlet的继承关系1.2 DispatcherServlet的doDispatch方法 2&#xff0c;核心组件HandlerMapping&#xff08;处理器映射器&#xff09;3&#xff0c;核心组件HandlerAdapter&#xff08;处理器适配器…

前端文艺复兴:Vue3真的需要Pinia吗?

前言 说起Pinia&#xff0c;熟悉 vue3 开发的程序员肯定不会陌生&#xff0c;甚至被vue官方推荐取代vuex&#xff0c;成为vue全家桶之一。 疑惑 还记得之前用 vuex 时&#xff0c;更改 state 还分同步和异步&#xff08;这里有尤雨溪的回答www.zhihu.com/question/48… &…

Hadoop-生产调优

第1章 HDFS-核心参数 1.1 NameNode内存生产配置 1&#xff09;NameNode 内存计算 每个文件块大概占用 150 byte&#xff0c;一台服务器 128G 内存为例&#xff0c;能存储多少文件块呢&#xff1f; 128 * 1024 * 1024 * 1024 / 150byte ≈ 9.1 亿G MB KB Byte 2&#xff09…

undefined symbol: avio_protocol_get_class, version LIBAVFORMAT_58

rv1126上进行编译和在虚拟机里面进行交叉编译ffmpeg都不行 解决办法查看 查看安装的ffmpeg链接的文件 ldd ./ffmpeg rootEASY-EAI-NANO:/home/nano/ffmpeg-4.3.6# ldd ffmpeg linux-vdso.so.1 (0xaeebd000)libavdevice.so.58 > /lib/arm-linux-gnueabihf/libavde…

continue语句

一、continue语句 1、continue语句介绍 2、continue语句流程图 3、快速入门案例 4、continue语句的标签

基于Go-Kit的Golang整洁架构实践

如何用Golang实现简洁架构&#xff1f;本文介绍了基于Go-Kit实现简洁架构的尝试&#xff0c;通过示例介绍了简洁架构的具体实现。原文: Why is Go-Kit Perfect For Clean Architecture in Golang? 简介 Go是整洁架构(Clean Architecture)的完美选择。整洁架构本身只是一种方法…

基于python+控制台的车辆信息管理系统

基于python控制台的车辆信息管理系统 一、系统介绍二、效果展示三、其他系统实现四、获取源码 一、系统介绍 打印功能菜单、添加车辆信息、删除车辆信息、修改车辆信息、显示车辆信息、退出系统&#xff0c;并且需要接收用户的输入&#xff0c;在根据输入内容调用相应函数实现…

深度学习介绍

对于具备完善业务逻辑的任务&#xff0c;大多数情况下&#xff0c;正常的人都可以给出一个符合业务逻辑的应用程序。但是对于一些包含超过人类所能考虑到的逻辑的任务&#xff0c;例如面对如下任务&#xff1a; 编写一个应用程序&#xff0c;接受地理信息、卫星图像和一些历史…

指针的深入理解(四)

这节主要讨论sizeof和strlen的区别&#xff0c;以及一些理解题。 sizeof 求的是对象的大小&#xff0c;深入理解一点就是&#xff1a;这个对象&#xff0c;他一定有一块对应的内存空间。求的就是这一块内存空间。 strlen 只能用来求字符串&#xff0c; 求取的是字符串的长度。…

Unity中blendtree和state间的过渡

混合树状态之间的过渡 如果属于此过渡的当前状态或下一状态是混合树状态&#xff0c;则混合树参数将出现在 Inspector 中。通过调整这些值可预览在混合树值设置为不同配置时的过渡表现情况。 如果混合树包含不同长度的剪辑&#xff0c;您应该测试在显示短剪辑和长剪辑时的过渡表…

Mocaverse NFT 概览与数据分析

作者&#xff1a;stellafootprint.network 编译&#xff1a;mingfootprint.network 数据源&#xff1a;Mocaverse NFT Collection Dashboard Mocaverse 是 Animoca Brands 推出的专属 NFT&#xff08;非同质化代币&#xff09;系列&#xff0c;包含 8,888 个独特的 "M…

深入理解TCP网络协议(3)

目录 1.前言 2.流量控制 2.阻塞控制 3.延时应答 4.捎带应答 5.面向字节流 6.缓冲区 7.粘包问题 8.TCP异常情况 9.小结 1.前言 在前面的博客中,我们重点介绍了TCP协议的一些属性,有连接属性的三次握手和四次挥手,还有保证数据安全的重传机制和确认应答,还有为了提高效率…

2024美赛E题成品论文22页详细讲解+完整代码数据汇总

E题社区抗灾能力综合评估与决策模型研究 &#xff08;完整版在文末&#xff09; 摘要&#xff1a;社区抗灾能力的提升对于灾害风险管理至关重要。本研究基于机器学 习方法&#xff0c;构建了社区抗灾能力预测模型&#xff0c;以评估社区在灾害事件中的表现。首先&#xff0c; 我…

在maven环境中使用GraalVM来构建本地原生应用程序(一)构建本地可执行文件

文章目录 前言一、GraalVM安装二、初步使用三、踩坑记录1、JSON转换问题2、反射、资源、jni的调用问题3、HTTPS调用问题4、Linux下CPU架构问题5、Linux下GLIBC版本的问题6、部分Windows系统无法缺少相关的库文件 总结 前言 随着Java17的更新&#xff0c;jdk又推出了一个GraalV…

【lesson10】高并发内存池细节优化

文章目录 大于256KB的大块内存申请问题大于256KB的大块释放申请问题使用定长内存池脱离使用new释放对象时优化为不传对象大小完整版代码Common.hObjectPool.hThreadCache.hThreadCache.cppConcurrentAlloc.hCentralCache.hCentralCache.cppPageCache.hPageCache.cpp 大于256KB的…

SpringBoot中数据库的连接及Mybatis的配置和使用

目录 1 在pom.xml中引入相关依赖 2 对数据库进行配置 2.1 配置application.yml 2.2 idea连接数据库 (3.2.1有用到) 3 Mybatis的使用 3.1 测试文件的引入 3.2 使用 3.2.1 使用注解(有小技巧(✪ω✪)) 3.2.2 使用动态sql 1 在pom.xml中引入相关依赖 <dependencies&g…