从内核层说清GetMessage , DispatchMessage

article/2025/11/4 8:17:15

文章目录

    • 要点回顾:
    • 为什么拿到句柄非得要回零环?
    • 消息队列(总共有7个小队列)结构
    • GetMessage的声明:
    • GetMessage进入内核:
    • GetMessage的功能总结:
    • DispatchMessage
    • 举例验证(有前提情况,仔细观察)
    • ```SendMessage```发送消息运行截图
    • ```PostMessage```发送消息运行截图

要点回顾:

一个GUI线程有一个消息队列:
普通线程–>GUI线程–>THREAD.W32THREAD -->THREADINFO–>消息队列

一个线程可以有多个窗口,所有窗口共享一个消息队列:
_WINDOW_OBJECT ---->PTHREADINFO pti //所属线程
---->WNDPROC IpfnWndProc //窗口过程(窗口回调函数)

为什么拿到句柄非得要回零环?

GetMessage(&msg, NULL, 0, 0)
TranslateMessage(&msg);
DispatchMessage(&msg);

这里消息msg的结构体成员如下:

typedef struct tagMSG {HWND   hwnd;UINT   message;WPARAM wParam;LPARAM lParam;DWORD  time;POINT  pt;DWORD  lPrivate;
} MSG, *PMSG, *NPMSG, *LPMSG;

这个消息里面存放着窗口的句柄,句柄是什么?句柄它仅仅是一个窗口对象的索引而已,并非当前对象地址,通过句柄找不到相应的窗口回调,它仅仅就是一个窗口对象索引值。窗口回调是存储在窗口对象里面的,如果需要找到窗口回调,那么我们就需要先找到窗口对象,而窗口对象在哪呢?(窗口与线程的关系)窗口都是由API进入零环去画出来,一切信息都在零环,这个知识点我们在前面已经说过。。

所以GetMessageTranslateMessageDispatchMessage拿着取出来的消息的句柄,进入零环,通过句柄找到相应的窗口对象,通过窗口对象找到相对于的窗口回调函数,然后内核进行调用回调函数。

这也就是为什么非得进入零环的原因。

消息队列(总共有7个小队列)结构

1.SentMessagesListHead //接到SendMessage发来的消息
2.PostedMessagesListHead //接到PostMessage发来的消息
3.HardwareMessagesListHead //接到鼠标,键盘的消息
…………
…………
根据前面的介绍,消息队列放在THREADINFOTHREADINFOKTHREAD结构体中,KTHREAD又在ETHREAD中)中:
在这里插入图片描述
USER_MESSAGE_QUEUE又分为七个小队列
在这里插入图片描述
在这里插入图片描述

GetMessage的声明:

GetMessage(LPMSG	IpMsg,			//返回从队列中摘下来的消息HWND	  hWnd,				//过滤条件一:(要取的是哪个窗口的消息,如果要专门取哪个窗口的消息,直接把句柄放在此处就行)发个这个窗口的消息UINT	wMsgFilterMin,		//过滤条件UINT    wMsgFilterMax		//过滤条件;

GetMessage进入内核:

GetMessage会调用内核层函数w32k!NtUserGetMessage,伪代码如下:

do{
//先判断SentMessageListHead
do{
……
KeUserModeCallBack(USER32_CALLBACK_WINDOWPROC,Arguments,ArgumentLength,&ResultPointer,&ResultLength);
…………
}while(SentMessageListHead!=NULL}while(其他队列!=NULL

在这里插入图片描述

进入后可以查看到这里有处理SentMessagesListHead 消息队列的函数:
在这里插入图片描述
然后进入后这是从0环回到3环的函数:
在这里插入图片描述
GetMessage只处理SendMessage发来的消息,原因可以看上图,而由PostMessage发来的消息,只是取出,并不会进行近一步处理操作

GetMessage的功能总结:

GetMessage(只处理第一个消息队列的消息,至于其它消息队列的消息,GetMessage只负责取出, 然后不管,继续向下传递)的主要功能:

  1. (第一个循环)首先会判断SentMessagesListHead 这个队列里面有没有消息,如果有的话,首先会把这个消息给处理掉(如何处理呢?也就是从0环回到3环,再来调用注册的窗口过程函数)
  2. (第二个循环:依次判断其他的6个队列,里面如果有消息,就返回,没有就继续取消息)循环判断是否有该窗口的消息,如果有,将消息存储到MSG指定的结构,并将消息从列表中删除(依次判断其他的6个队列,里面如果有消息 返回,没有 继续)
    它会首先看SentMessagesListHead 这个队列,如果有的话,会就地处理

DispatchMessage

DispatchMessage(&msg)//消息的分发,根据窗口句柄调用相关的窗口过程,通过不同的句柄,进入零环找到不同的窗口对象,然后根据窗口对象找到回调函数,并且调用回调函数。

即其他6个消息队列的处理流程:
User32!DispatchMessage调用w32k!NtUserDispatchMessage

  1. 根据窗口句柄找到窗口对象
  2. 根据窗口对象找到窗口过程处理函数,由0环发起调用
    在这里插入图片描述

举例验证(有前提情况,仔细观察)

TranslateMessage(&msg);DispatchMessage(&msg);注释掉后,只剩GetMessage(&msg, NULL, 0, 0),然后利用其它程序PostMessage(hwnd, 0x0401, NULL, NULL);SendMessage(hwnd, 0x0401, NULL, NULL);分别发送消息
前提情况:(特别注意)
在这里插入图片描述

SendMessage发送消息运行截图

SendMessage(hwnd, 0x0401, NULL, NULL);

在这里插入图片描述
下图中我们可以看到
在这里插入图片描述
当我们未点击确定时,发送消息的程序未退出,需要点击确定后,发送消息的程序收到返回消息,它才会自行退出。这也就是SendMessage的同步问题

当点击确定后,发送消息程序的运行截图:
在这里插入图片描述

PostMessage发送消息运行截图

PostMessage(hwnd, 0x0401, NULL, NULL);

发送消息的运行截图:
在这里插入图片描述
接收消息的运行截图:
在这里插入图片描述
这里充分说明了上述情况,GetMessage并不会处理PostMessage发送的消息。

注意:
PostMessage发送完消息后,程序即刻退出,并不会等待处理结果,这也就是PostMessage发送消息异步问题


http://chatgpt.dhexx.cn/article/2ETpEN6C.shtml

相关文章

Message的消息池(sPool)

关键总结 1、消息池缓存有可重复使用的消息实例,避免过多的创建与回收消息实例 2、消息池是一个栈(LIFO/FILO后进先出/先进后出)的数据结构,具体的数据存放是采用了链表方式 3、消息池一开始是空的,需要主动添加消息进…

信息炸弹——Message Boom

前言 好的今天我们来讨论一下什么叫信息炸弹。 可能之前看过我文章的小伙伴们在想,这种听名字就具有攻击性的东西为什么不把它放到黑客七宗罪专栏里? 毕竟这只是个脚本,对于个人账号的攻击性确实强,聊天记录也会占用硬盘。但是…

handler+message【消息机制】

🍖🍖 作者 : 不良使 🍖🍖🍖🍖 潜力创作新星 华为云享专家 🍖🍖🍖🍖🍖 PythonAndroid 🍖🍖🍖&#…

c++中MessageBox弹窗的用法大全

想必大家都知道&#xff0c;MessageBox函数是c语言中很常用且好玩的函数之一&#xff0c;那你知道它怎么用吗&#xff1f; 这是MessageBox函数的标准格式之一&#xff0c;本人喜欢用这种格式&#xff0c;注意函数的大小写&#xff01; MessageBox不在 #include<bits/stdc.h&…

message broker

MB概述 MB的全称是message broker&#xff0c;即“消息代理”。“消息”一词前几年比较火&#xff0c;消息中间件也卖的很火&#xff0c;当时似乎J2EE的产品都要跟“消息”、“中间件”扯上点关系&#xff0c;以彰显潮流。我觉得初学者只需记住“消息”的异步性即可&#xff0c…

MP3音频文件格式(MPEG-1 audio layer 3)

MP3音频文件格式 【百度百科】mp3 &#xff08;一种音频编码方式&#xff09; 【维基百科】MP3&#xff08;本文重定向自 MPEG-1 Audio Layer 3&#xff09; MP3(MPEG-1 audio layer 3) MPEG-1音频分三层&#xff0c;分别为 MPEG-1 Layer1&#xff0c;MPEG-1 Layer2 以及 MPE…

怎么把wav文件改成mp3?

怎么把wav文件改成mp3&#xff1f;有过摄像摄影经历的小伙伴都应该认识wav&#xff0c;wav就是他们作品的保存格式。因为wav格式的文件体积特别大&#xff0c;在储存的时候会占用我们大量的内存&#xff0c;而且为了播放方便&#xff0c;我们通常要把wav文件改成mp3格式的&…

音频文件如何转成mp3格式

当提到音频文件格式时&#xff0c;大家往往会想到最为流行和广泛使用的mp3格式。mp3是一种广受欢迎的音频格式&#xff0c;因为各种音频格式自身特点的原因&#xff0c;所以将其他格式的音频文件转换成mp3是非常普遍的需求。就比如在我们日常生活中&#xff0c;下载到的各种格式…

如何转换音频格式为mp3?

一提到音乐&#xff0c;大家先想到的应该就是MP3了&#xff0c;既然MP3作为常用的&#xff0c;被大家所熟知的一种音频格式&#xff0c;那它必定有其他格式无可比拟的优点。其实mp3从功能上来讲它具有更强的携带性和传输性&#xff0c;利于保存和分享&#xff1b;其次MP3本身的…

电脑音频转换mp3格式怎么弄,教你音频怎么转换mp3格式

mp3格式是目前几乎全兼容的格式了&#xff0c;在我们参加一些会议或讲座时&#xff0c;需要录制一些重要的信息&#xff0c;结束后再进行复盘或分享。然而&#xff0c;不同的录制工具录制的音频格式也不同&#xff0c;这时使用软件将音频统一成mp3格式的话&#xff0c;就会方便…

免费在线MP3转换器:将音乐文件转换为MP3格式

在今天的数字时代&#xff0c;音乐成为了人们生活中不可或缺的一部分。然而&#xff0c;由于音乐文件格式的不同&#xff0c;我们有时可能无法在不同的设备上播放我们最喜爱的歌曲。MP3格式作为最常用的音乐文件格式之一&#xff0c;通常可以被几乎所有的设备支持&#xff0c;因…

mp3格式怎么弄?分享三个音频文件格式转换的方法

不知道小伙伴们有没有遇到过这样的情况&#xff0c;在网上下载一首歌下来&#xff0c;正想打开&#xff0c;结果却发现我们的播放器无法播放。你们知道这是为什么嘛&#xff0c;其实我们的音频文件是有很多不同的格式&#xff0c;其中就有些比较少见的格式&#xff0c;我们的音…

如何从MP4视频文件中抽取MP3音频?

简 介&#xff1a; 为了能够处理视频中的音频&#xff0c;测试了两种提取视频中的音频方法。一种是利用格式工程软件另外一种利用ffmpeg软件。 关键词&#xff1a; 视频文件&#xff0c;音频文件&#xff0c;mp4&#xff0c;mp3 #mermaid-svg-sPs0isryqtLTjZyg {font-family:&q…

如何将音频文件转换为MP3格式?

音频文件有很多种格式&#xff0c;如 WAV、FLAC、AAC 等&#xff0c;其中 MP3 是最为常见的一种格式&#xff0c;因为它具有压缩比高、音质损失少、兼容性强等优点&#xff0c;适合在各种设备上播放。如果你想将一个音频文件转换为 MP3 格式&#xff0c;可以采用以下几种方法&a…

Next() Nextline() hasNext()区别

next类和hasNext方法遇到缓冲区没数据时&#xff0c;会阻塞&#xff0c;等待输入后next类会读取&#xff0c;hasNext会返回true 1&#xff09;nextLine nextLine&#xff08;&#xff09;方法返回的是"\n"之前的所有字符&#xff0c;它是可以得到带空格的字符串的。 …

BNext

又搬来了大神器啊 来自德国HassoPlattner计算机系统工程研究院的NianhuiGuo和HaojinYang等研究者提出了BNext模型&#xff0c;成为第一个在ImageNet数据集上top1分类准确率突破80%的BNN。 两年前&#xff0c;依靠早期 BNN 工作 XNOR-Net 起家的 XNOR.AI 被苹果公司收购&#…

Next.js学习笔记

这是一个用于生产环境的React 框架&#xff0c;Next.js 为您提供生产环境所需的所有功能以及最佳的开发体验&#xff1a;包括静态及服务器端融合渲染、 支持 TypeScript、智能化打包、 路由预取等功能 无需任何配置。 create-next-app 使用 create-next-app创建新的 Next.js …

搭建vue3项目时出现Cannot read property ‘nextSibling‘ of null报错

记录自己学习中&#xff0c;出现的错误 在搭建vue3项目&#xff0c;配置router&#xff0c;vuex,element-ui后&#xff0c;运行项目页面白屏&#xff0c;控制台出现了Cannot read property nextSibling of null的错误 查看main.ts 文件&#xff0c;此时的写法是&#xff1a; …

hasNext、hasNextLine、next、nextLine保姆级详解

目录 前言 hasNext和hasNextLine的区别 hasNext 和 next组合 hasNext 和 NextLine组合 hasNextLine 和 next组合 hasNextLine 和 nextLine组合 验证hasNext、hasNextLine对输入代码的存储寿命 总结 前言 在查阅了大量网上相关资料都没有一个完整的解释&#xff0c;并且我…

细节!关于Java中的next与nextLine

目录 一、发现问题 二、解决问题 &#xff08;1&#xff09;输入连续字符串 &#xff08;2&#xff09;输入不连续字符&#xff08;含有空格等&#xff09; &#xff08;3&#xff09;nextLine()方法在前&#xff0c;next()方法在后 &#xff08;4&#xff09;next()方法在…