Windows SDK 消息类型详解

news2024/12/25 9:00:58

消息结构体

如下是消息的结构体

typedef struct tagMSG
{
    HWND hwnd;      // 消息所属窗口的句柄
    UINT message;   // 消息的标识符,表示什么类型的消息,如WM_PAINT、WM_QUIT等。
    WPARAM wParam;  // 与消息相关的附加信息。具体含义取决于消息的类型。
    LPARAM lParam;  // 与消息相关的附加信息。具体含义取决于消息的类型。
    DWORD time;     // 消息被创建的时间(系统启动后的毫秒数)。
    POINT pt;       // 消息发生时的光标位置,相对于屏幕的坐标。
    DWORD lPrivate; // 私有字段,用于操作系统内部使用,应用程序通常不使用此字段。
} MSG, *PMSG, *NPMSG, *LPMSG;

我们通过观察消息的结构体可知:窗口过程函数的四个参数就是MSG消息结构体前四个字段MSG里的time和pt成员是给操作系统用的,操作系统使用到了这些成员,放置到相应线程的消息队列中。

消息的产生

当我们对某个窗口进行操作时,这个行为就会产生一个消息。操作系统最先得到这个消息,之后会判断这个消息要发送给哪个窗口,操作系统找到窗口后将这个消息放到这个窗口对象所属线程的消息队列中。应用层的GetMessage不停地从消息队列中取消息,取出来的消息放在MSG结构体中

消息的处理流程

我们对窗口的任意操作,实际上就是一个消息。从MSG结构体中的HWND成员可以看出,消息是针对窗口的。但MSG消息结构体中只有窗口对象的句柄HWND,没有窗口过程函数的信息。因此操作系统就需要调用DispatchMessage(&msg)函数根据句柄HWND找到窗口过程函数(根据HWND进入内核查找全局窗口句柄表,找到窗口对象,找到这个窗口对象的窗口过程函数)。最后由内核发起调用,执行窗口过程函数,将消息处理掉。

下图便是消息处理的过程:

消息类型

接下来我们以一个空白窗口过程函数,逐步优化进行讲解

LRESULT CALLBACK WindowProc(HWND hwnd,     // 窗口句柄
    UINT uMsg,     // 消息标识
    WPARAM wParam, // 附加消息信息
    LPARAM lParam) // 附加消息信息
{
    return DefWindowProc(hwnd, uMsg, wParam, lParam); // 默认窗口处理函数
}

能产生消息的四种情况:鼠标,键盘,其他的应用程序,操作系统的内核程序。每种消息都有一个编号,对应的字段是MSG.message

现在我们在窗口过程函数中打印uMsg字段,体会下消息

LRESULT CALLBACK WindowProc(HWND hwnd,     // 窗口句柄
    UINT uMsg,     // 消息标识
    WPARAM wParam, // 附加消息信息
    LPARAM lParam) // 附加消息信息
{
    char szOutBuff[0x80];
    sprintf(szOutBuff, "Message: %x - %x \n", hwnd, uMsg);
    OutputDebugString(szOutBuff);

    return DefWindowProc(hwnd, uMsg, wParam, lParam); // 默认窗口处理函数
}

此时运行程序,但我们并不对窗口进行操作,发现消息是不停的产生的。这是因为除了用户的鼠标,键盘,还可能有其他的应用程序,操作系统内核程序发的消息。

在上图中,每个uMsg字段都对应着一种消息,比如1就是对应WM_CREATE,意思就是窗口被创建。

接下来,我们开始讲解不同的消息

窗口关闭消息

我们可以对窗口进行拖动,最小化,最大化等操作,这是因为程序用了默认窗口过程函数来处理了这些消息DefWindowProc(hwnd, uMsg, wParam, lParam);。而在实际开发中,我们只需要针对自己需要的消息进行处理即可,其他的就交给默认的窗口过程函数。

窗口退出的消息是WM_DESTROY,现让我们对该消息进行填写:

LRESULT CALLBACK WindowProc(HWND hwnd,     // 窗口句柄
    UINT uMsg,     // 消息标识
    WPARAM wParam, // 附加消息信息
    LPARAM lParam) // 附加消息信息
{
    switch (uMsg) 
    {
        case WM_DESTROY:            // 当窗口关闭则退出进程
        {
            PostQuitMessage(0);
            break;
        }
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam); // 默认窗口处理函数
}

在上图代码中case WM_DESTROY的内容便是我们做出的针对窗口关闭的处理代码。当用户点击窗口关闭按钮时,进程退出。如果没有这段代码,关闭窗口就只是关闭窗口,进程仍然存在

键盘消息

键盘按下消息是WM_KEYDOWN。

当uMsg是WM_KEYDOWN消息时:

wParam:非系统键的虚拟键代码,用来记录按下哪一个键

lParam:32位大小,包含了与按键事件相关的额外信息:

0-15位:重复计数(表示自上次消息以来按键被按下的次数)

16-23位:扫描码(表示按键的硬件扫描码)

24位:扩展键标志(如果是由扩展键生成的,则该位为1)

25-28位:保留,不使用

29位:上下文代码(如果在中断时发出,则该位为1)

30位:先前的键状态(如果按键之前已经按下,则为1;如果之前未按下,则为0)

31位:转换状态(如果消息是由转换状态(例如将非字符键转换为字符键)生成的,则该位为1)

注意:键盘原生的消息是虚拟键消息。如果想得到字符消息,那么在DispatchMessage分发消息前需要调用TranslateMessage进行消息转换

 WM_KEYDOWN和WM_CHAR区别:

WM_KEYDOWNWM_CHAR是Windows编程中用于处理键盘输入的两种不同类型的消息,它们在处理键盘事件时有着明显的区别:

WM_KEYDOWN:

1.这是一个虚拟键消息,当用户按下键盘上的任何键时,就会触发WM_KEYDOWN消息

2. 它提供了虚拟键码(wParam参数),表示被按下的键。例如,如果按下回车键,虚拟键码将是VK_RETURN

3. WM_KEYDOWN消息用于处理键盘上的非字符键(如功能键、控制键等)以及字符键

4. lParam参数提供了关于按键事件的额外信息,如按键的重复计数、扫描码、是否是扩展键等

WM_CHAR:

 1.这是一个字符消息,当用户按下能产生字符的键时,就会触发WM_CHAR消息。

 2.WM_CHAR消息通过wParam参数提供实际的字符代码,这通常对应于按键生成的字符,考虑了键盘布局、按下的是大写键还是小写键、是否同时按下了Shift键等。

 3.WM_CHAR适合处理可打印字符的输入,如文本输入。不会为非字符键生成WM_CHAR消息。

 4.与WM_KEYDOWN不同,WM_CHAR不关心按键的物理位置或特定的硬件键

总的来说,WM_KEYDOWN消息更多地关注物理键盘上的键的状态,而WM_CHAR消息关注的是这些按键操作所产生的字符。在编写需要处理文本输入的应用程序时,通常会更多地关注WM_CHAR消息,因为它提供了对应于用户按键的实际字符。而WM_KEYDOWN则适用于那些需要处理非字符键(如方向键、功能键等)的场景。

更多的消息

case WM_CREATE:窗口创建时触发的消息

case WM_MOVE:窗口移动时触发的消息

case WM_SIZE:窗口大小改变时触发的消息

case WM_DESTROY:窗口关闭时触发的消息

case WM_KEYUP:键盘键释放时触发的消息

case WM_KEYDOWN:键盘键按下时触发的消息

case WM_LBUTTONDOWN:鼠标左键按下时触发的消息

case WM_COMMAND:鼠标左键点击控件

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

模型驱动设计(MODEL-DRIVEN DESIGN)

前言 为了保证软件实现得简洁并且与模型保持一致,不管实际情况如何复杂,必须运用建模和设计的最佳实践。 本书中的软件设计风格主要遵循"职责驱动设计"的原则,这个原则是Wirfs-Brock等人在1990年中提出的,并在2003年进…

Nios ll软核处理器

1.打开软件 (1)quartus软件内部打开 (2)创建软件快捷方式 软件安装目录文件夹下,nois2eds -> bin -> eclipse-nios2.exe ,创建快捷方式,放到桌面,双击打开软件。 2.Workspa…

CSC2121 半桥驱动芯片

CSC2121 X系列是一款高性价比的半桥架构的栅极驱动专用电路,用于大功率MOS管、IGBT管栅极驱动。CSC2121内部集成了逻辑信号处理电路、死区时间控制电路、欠压保护电路、电平位移电路、脉冲滤波电路及输出驱动电路,CSC2121X专用于无刷电机控制器中驱动电路…

韩国服务器的性能如何提升

韩国服务器的性能可以通过硬件升级、网络优化、缓存优化和软件优化来提升。具体方法如下,rak小编为您整理发布韩国服务器的性能如何提升。 1. 硬件升级 CPU升级:选择高性能的多核处理器,可以显著提升计算速度和响应能力。 内存升级&#xff1…

9.内置函数

目录 1.日期函数 案例1: 创建一张表,记录生日 案例2: 创建一个留言表 2.字符串函数 charset案例1->返回字符串字符集 concat案例连接字符串 instr案例 ​编辑 ucase案例 lcase案例 left案例 length案例 replace案例 strcmp…

13 定时器

13 定时器 1、定时1.1 硬件定时器的特性1.2 硬件定时器对应的中断处理函数所作的工作(了解)1.3 linux内核中跟时间相关的三个概念: 2、延时2.1.延时定义2.2 忙等待2.3.休眠等待2.4 等待队列机制2.4.1 介绍2.4.2 结论2.4.3 进程休眠和唤醒的编程步骤方法 1方法 2 3、…

Epic Games 商店面向欧盟 iPhone 用户上线

Epic Games Store 终于在欧盟推出,为玩家提供了不通过 App Store 就能在 iPhone上访问游戏的途径。在经历了漫长而昂贵的关于支付和竞争对手应用程序店面的法律战,以及公证方面的麻烦之后,Epic Games 成功地为App Store 带来了一个数字店面。…

IO多路复用中的水平触发和边缘触发、Java NIO中的水平触发举例

基础原理 水平触发(Level-triggered,也被称为条件触发)LT:主要满足条件,就触发事件。 边缘触发(Edge-triggered)ET:当状态变化时触发。 使用脉冲信号来说明LT和ET:LT指…

Nginx--地址重写Rewrite

一、什么是Rewrite Rewrite对称URL Rewrite,即URL重写,就是把传入Web的请求重定向到其他URL的过程 URL Rewrite最常见的应用是URL伪静态化,是将动态页面显示为静态页面方式的一种技术。比如http://www.123.com/news/index.php?id123 使用U…

Linux命令之一

Linux命令之一 帮助类命令磁盘管理文件管理系统设置开关服务命令临时开关服务命令永久开关服务命令 压缩/解压网络通讯网络访问管道和重定向搜索命令grepfind 磁盘分区类命令 Linux命令速查平台 帮助类命令 语法 man [命令或配置文件] (功能描述:获得帮助…

【c++】深入理解别名机制--引用

🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C 目录 前言 一、引用的概念和定义 二、引用的特性 三、引用的实用性 1.引用传参 2.引用做返回值 2.1 引用做返回值的作用 2.2 引用坍缩问题、悬挂引用问…

ThreadPoolExecutor详解

恰逢经济下行,鄙人工作、生活日趋艰难,原本美好的愿望,如今只能成为奢望。不知如何是好的我,只能精研近几年来因浮躁而荒废的知识。今天就想跟大家聊一个对我来讲看似熟悉实则陌生的工具——ThreadPoolExecutor。熟悉是因为在我负…

【nacos 第二篇章】动手实践(从零代码开发版)

一、环境准备 本章将通过手把手的教程一步一步教你如何从零开发一个微服务应用。 首先需要安装好 nacos 服务并启动。安装 nacos 服务请看作者的 【nacos 第一篇章】安装一下 nacos 文章。 二、初始化项目 如上图所示,可以建立一个基础的项目。 搭建了基础项目之…

计算机毕业设计 在线项目管理与任务分配系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

节点使用简介:comfyui-photoshop

1、安装comfyui-photoshop 略过 一点要注意的是:在Photoshop上的安装增效工具,要通过Creative Cloud 桌面应用程序进行安装,才能成功在增效工具中显示,直接通过将文件解压到Plug-ins路径行不通(至少对我来说行不通&am…

通过剪枝与知识蒸馏优化大型语言模型:NVIDIA在Llama 3.1模型上的实践与创新

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

阿里云ACP的三种报名与对应题库获取方式的详细说明(按费用排序)

文章目录 前言方式一、官方途径(较为昂贵)考试资格获取官方视频教程获取方式总结 方式二、报名机构(价格适中,考取速度快)推荐机构大概费用机构报名方式机构报名后所携带的内容或者说对于其他方法有什么优势总结 方式三、闲鱼(最便宜,但题库有风险)考试资…

C语言 之 strstr函数的使用和模拟、strtok函数的使用、strerror函数和perror函数的使用

文章目录 strstr 的使用和模拟实现strstr函数模拟实现 strtok 函数的使用例子1例子2例子3 strerror 函数的使用perror函数 strstr 的使用和模拟实现 函数原型: const char * strstr ( const char * str1, const char * str2 ); 该函数能够查找str1中第一次出现str2…

产业经济大脑建设方案(五)

为了提升产业经济的智能化水平,我们提出建设一个综合产业经济大脑系统,该系统通过整合大数据分析、人工智能和云计算技术,构建全方位的数据采集、处理和决策支持平台。该平台能够实时监测产业链各环节的数据,运用智能算法进行深度…

Unified 阻抗控制 architecture、framework、approach

Unified 阻抗控制(Unified Impedance Control)作为一种控制策略,其architecture(架构)、framework(框架)和approach(方法)为: 一、Unified 阻抗控制 Archite…