翻译《The Old New Thing》 - Restating the obvious about the WM_COMMAND message

Restating the obvious about the WM_COMMAND message - The Old New Thing (microsoft.com)icon-default.png?t=N7T8https://devblogs.microsoft.com/oldnewthing/20060302-10/?p=32093

Raymond Chen 2006年03月02日


关于 WM_COMMAND 消息的显而易见的知识点补充

 

简要

        本文详细解释了 WM_COMMAND 消息的用途和参数,包括三种触发该消息的情景:菜单选择、控件通知和加速键击。wParam 参数的高字节表示通知代码,低字节表示控件或菜单项的标识符。lParam 参数是控件句柄,如果是菜单或加速器则为 NULL。文章还讨论了 WM_NOTIFYWM_COMMAND 的区别,并指出在早期 Windows 版本中,由于 WM_NOTIFY 不可用,控件通常使用 WM_COMMAND 进行通知。最后,文中通过代码示例说明了如何手动生成这些消息。

正文

        我对 MSDN 上关于 WM_COMMAND 消息的文档很满意,但为了更进一步的完整性,我将陈述一些显而易见的内容,希望你们,亲爱的读者,能够利用这些技术来填补MSDN其他部分的空白。

  WM_COMMAND 消息的一行摘要说: “当用户从菜单中选择一个命令项,当一个控件向其父窗口发送一个通知消息,或者当一个加速键击被翻译时,会发送 WM_COMMAND 消息。”

        简而言之,有三种情况会生成 WM_COMMAND 消息,即上述列出的三种。你应该将 WM_COMMAND 消息的菜单和加速器情况视为控件情况的特殊情况。

  wParam 参数的高字节“如果消息来自控件,则指定通知代码。” 这里的“控件”是什么意思? 记住,你必须根据上下文来考虑事物。 WM_COMMAND 消息是在 Win32 的一般上下文中,特别是窗口管理器的上下文中提出的。 通常称为“控件”的窗口,如编辑框、按钮和列表框,以及“公共控件库”中的所有窗口类都是如此。 在窗口管理器的世界里,一个“控件”是一个窗口,其目的是为其父窗口提供一定程度的交互性(在静态控件的情况下,可能根本没有交互性)。

  WM_COMMAND 主要用于对话框的上下文,进一步强调了这里的“控件”一词只是“子窗口”的同义词。

        “通知代码”在这里意味着什么? 控件通知代码是由控件本身定义的任意16位值。 按照惯例,它们被命名为 xxN_xxxx,其中“N”代表“通知”。 然而,要小心,不要将其与 WM_NOTIFY 消息相关联的通知代码混淆。 幸运的是,每个通知代码在其文档中都指定了它是作为 WM_COMMAND 通知还是 WM_NOTIFY 通知到达的。

        现代控件设计师更有可能使用 WM_NOTIFY 通知,因为它们允许随通知传递额外的信息。 相比之下,WM_COMMAND 消息只传递通知本身;WM_COMMAND 消息的其他参数是强制的,如下所示。

        如果 WM_NOTIFYWM_COMMAND 更优越,为什么一些控件使用 WM_COMMAND? 因为 WM_NOTIFY 直到 Windows 95 才可用。 在 Windows 95 之前编写的控件不得不满足于使用 WM_COMMAND 消息。

        “如果消息来自加速器,这个值【wParam 参数的高字节】是 1。” 记住,我们仍然在窗口管理器的上下文中,特别是在 WM_COMMAND 消息的上下文中。 这里的加速器指的是在消息循环中调用 TranslateAccelerator 生成的消息。

        “如果消息来自菜单,这个值是零。” 如果 WM_COMMAND 消息是由用户从菜单中选择一个项触发的,那么 wParam 的高字节是零。

  wParam 参数的低字节“指定菜单项、控件或加速器的标识符。” 菜单项或加速器的标识符是你在菜单或加速器模板中与之关联的命令代码,或者(在菜单项的情况下)当你使用像 InsertMenuItem 这样的函数手动创建菜单项时。

        你可能会将你的菜单项标识符和加速器标识符命名为 IDM_something。) 控件的标识符由控件的创建者确定;回想一下,CreateWindowCreateWindowEx 函数的 hMenu 参数如果你正在创建子窗口,它被视为子窗口标识符。 那就是控件标识符。 (你可以通过调用 GetDlgCtrlID 函数来检索控件的标识符。

        最后,lParam 参数是“如果消息来自控件,则为发送消息的控件的句柄。否则,此参数为 NULL。” 如果通知是由子窗口生成的(显然具有适合该子窗口的通知代码),那么该子窗口句柄将作为 lParam 传递。 如果通知是由加速器或菜单生成的,那么 lParam 是零。

        注意,WM_COMMAND 消息的几乎所有参数一旦你决定了你要生成什么通知,都是强制的。

        如果你正在从控件生成通知,你必须在 wParam 的高字节中传递通知代码,在 wParam 的低字节中传递控件标识符,并将控件句柄作为 lParam 传递。换句话说,一旦你决定 hwndC 窗口想要发送一个 CN_READY 通知,你别无选择,只能这样写:

SendMessage(GetParent(hwndC), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwndC), CN_READY), (LPARAM)hwndC);

        换句话说,所有控件通知都采用以下形式:

SendMessage(GetParent(hwndC), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwndC), notificationCode), (LPARAM)hwndC);

        其中 hwndC 是生成通知的控件,notificationCode 是通知代码。 当然,如果你更愿意发布通知而不是发送它,你可以使用 PostMessage 而不是 SendMessage

        其他两种情况(加速器和菜单)通常不是你通常会编码的情况,因为你通常让 TranslateAccelerator 函数处理加速器,让菜单系统处理菜单标识符。 但是,如果出于某种原因,你想假装用户输入了一个加速器或选择了一个菜单项,你可以通过遵循文档中规定的规则手动生成通知。

// 模拟加速器 IDM_WHATEVER 
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_WHATEVER, 1), 0);

        在这里,hwnd 是你想要假装被传递到 TranslateAccelerator 函数的窗口,IDM_WHATEVER 是加速器标识符。

        模拟菜单选择完全相同,只是(根据上述规则),你将 wParam 的高字节设置为零。

// 模拟菜单项 IDM_WHATEVER
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_WHATEVER, 0), 0);

        在这里,hwnd 是与菜单关联的窗口。 一个窗口可以通过以下方式与菜单关联:通过菜单(通过将菜单句柄传递给 CreateWindowCreateWindowEx 函数显式创建,或者通过在类注册中包含它隐式创建)或通过将菜单显式作为窗口参数传递给像 TrackPopupWindow 这样的函数。

        加速器/菜单情况和控件通知情况之间的一个显著区别是,加速器和菜单标识符由调用应用程序定义,而控件通知由控件定义。

        你可能已经注意到了利用控件通知代码的双关特性的机会。如果一个控件将通知代码定义为零,那么它将“看起来像”菜单项选择,因为在菜单项选择的情况下wParam的高字节是零。

        按钮控件利用了这个双关特性:

#define BN_CLICKED 0

        这意味着,当用户点击按钮控件时,生成的WM_COMMAND消息“闻起来像”菜单选择通知。你可能在没有意识到的情况下在你的对话框程序中利用了这一点。

        静态控件也利用了这个双关特性:

#define STN_CLICKED 0

        但是,为了使静态控件生成 STN_CLICKED 通知,你必须设置 SS_NOTIFY 样式。

        我在开始时说,加速器和菜单情况只是控件情况的特殊情况。 如果你将 WM_COMMAND 消息的各个部分分开,你会发现它们分为两类:

  • 发生了什么?(通知代码。)
  • 发生在谁身上?(控件句柄和ID。)

        在菜单或加速器的情况下,“发生了什么?”是“用户点击了菜单(0)”或“用户输入了加速器(1)”。 “发生在谁身上?”是“这个菜单ID”或“这个加速器ID”。 由于通知不是来自控件,控件句柄是 NULL

       如果这对你们来是显而易见的, 我向 Win32 程序员道歉。

       现在你已经是 WM_COMMAND 消息的专家了,也许你可以解决这个人的问题。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文读懂ipv4和ipv6的区别

IPv4和IPv6是互联网协议的两个主要版本,它们在多个方面存在显著的差异。以下是关于IPv4和IPv6之间区别的详细探讨: 一、地址空间 IPv4使用32位地址,理论上可以表示约42.9亿个不同的地址。然而,由于地址分配的不均衡以及网络技术的…

清华团队开发首个AI医院小镇模拟系统;阿里云发布通义千问 2.5:超越GPT-4能力;Mistral AI估值飙升至60亿美元

🦉 AI新闻 🚀 清华团队开发首个AI医院小镇模拟系统 摘要:来自清华的研究团队最近开发出了一种创新的模拟系统,名为"Agent Hospital",该系统能够完全模拟医患看病的全流程,其中包括分诊、挂号、…

element ui的确认提示框按钮样式修改

修改确认提示框的默认按钮样式,使用css强制修改 例: js代码: deleteUser(params){this.$confirm("您确定要删除吗?此操作无法撤销并且将永久删除所有数据。", "提示", { type: "warning", cancel…

批量自定义重命名,一键添加顺序编号,文件夹管理更高效!

我们经常需要对文件夹进行管理和整理。然而,当面对大量需要改名的文件夹时,手动逐个修改不仅效率低下,还容易出错。那么,有没有一种方法能够批量自定义重命名文件夹,并在名称后自动添加顺序编号呢?答案是肯…

JS执行原理大揭秘:事件循环Event Loop与宏任务、微任务

前言 📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步! 🍅 个人主页:南木元元 目录 事件循环概述 异步和单线程 同步任务 异步任务 任务队列 宏任务 微任务…

智慧手术室手麻系统源码,C#手术麻醉临床信息系统源码,符合三级甲等医院评审要求

手麻系统全套源码,C#手术麻醉系统源码,支持二次开发,授权后可商用。 手术麻醉临床信息系统功能符合三级甲等医院评审要求,实现与医院现有信息系统如HIS、LIS、PACS、EMR等系统全面对接,全面覆盖从患者入院,…

精准读取CSV/Excel数据 - 灵活指定行列范围的 Python 解决方案

文章目录 源代码项目简介导入相关库__file_exists 装饰器函数的签名和注释主要功能的实现运行演示读取 Excel 文件 源代码 https://github.com/ma0513207162/PyPrecip。pyprecip\reading\read_api.py 路径下。 项目简介 PyPrecip 是一个专注于气候数据处理的 Python 库&#xf…

9.为什么有时候会“烫烫烫”——之函数栈桢

目录 1. 什么是函数栈帧 2. 理解函数栈帧能解决什么问题呢? 3. 函数栈帧的创建和销毁解析 3.1 什么是栈? 3.2 认识相关寄存器和汇编指令 3.3 解析函数栈帧的创建和销毁 小知识:烫烫烫~ Q&A 1. 什么是函数栈帧 我们在写C语言代码…

大模型面试常考知识点1

文章目录 1. 写出Multi-Head Attention2. Pre-Norm vs Post-Norm3. Layer NormRMS NormBatch Norm 4. SwiGLU从ReLU到SwishSwiGLU 5. AdamW6. 位置编码Transformer位置编码RoPEALibi 7. LoRA初始化 参考文献 1. 写出Multi-Head Attention import torch import torch.nn as nn …

毕业设计参考-PyQt5-YOLOv8-鱼头鱼尾鱼长测量程序,OpenCV、Modbus通信、YOLO目标检测综合应用

“PyQt5-YOLOv8-鱼头鱼尾鱼长测量程序”是一个特定的软件程序,用于通过图像处理和目标检测技术来测量鱼类的长度。 视频效果: 【毕业设计】基于yolo算法与传统机器视觉的鱼头鱼尾识别_哔哩哔哩_bilibili 这个程序结合了多种技术: 1. OpenCV…

链表第7/9题--链表相交--双指针

leetcode160: 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意&#xf…

记录如何查询域名txt解析是否生效

要查询域名的TXT记录,可以使用nslookup命令。具体步骤如下:12 打开命令行终端。输入命令 nslookup -qttxt 域名,将"域名"替换为你要查询的实际域名。执行命令后,nslookup会返回域名的TXT记录值。 如何查询域名txt解析是…

厂家自定义 Android Ant编译流程源码分析

0、Ant安装 Windows下安装Ant: ant 官网可下载 http://ant.apache.org ant 环境配置: 解压ant的包到本地目录。 在环境变量中设置ANT_HOME,值为你的安装目录。 把ANT_HOME/bin加到你系统环境的path。 Ubuntu下安装Ant: sudo apt…

基于 Linux 自建怀旧游戏之 - 80 款 H5 精品小游戏合集

1)简介 最近又找到了一款宝藏游戏资源分享给大家,包含 80 款 H5 精品小游戏,都是非常有趣味耐玩的游戏,比如 植物大战僵尸、捕鱼达人、贪吃蛇、俄罗斯方块、斗地主、坦克大战、双人五子棋、中国象棋 等等超级好玩的 H5 小游戏&…

添加对象方法

添加对象方法的方法如下,这是一个通用模式 注意灵活运用。

Python深度学习基于Tensorflow(4)Tensorflow 数据处理和数据可视化

文章目录 构建Tensorflow.data数据集TFRecord数据底层生成TFRecord文件数据读取TFRecord文件数据图像增强 数据可视化 构建Tensorflow.data数据集 tf.data.Dataset表示一串元素(element),其中每个元素包含一个或多个Tensor对象。例如&#xf…

如何在IDEA中找到jar包路径对应的maven依赖

1.找到文件所对应的jar包路径 2.按照箭头顺序操作 3.查找文件所对应的依赖

商场综合体能源监管平台,实现能源高效管理

商场作为大型综合体建筑,其能源消耗一直是备受关注的问题。为了有效管理商场能耗,提高商场能源效率,商场综合体能源监管平台应运而生。 商场综合体能源监管平台可通过软硬件一起进行节能监管,硬件设备包括各种传感器、监测仪表和…

FastReID使用教程、踩坑记录

近期在尝试使用FastReID,期间对FastReID架构、损失函数、数据集准备、模型训练/评估/可视化/特征向量输出、调试debug记录等进行记录。 FastReID架构理解 关于FastReID的介绍,可点击此链接前往查询。 ReID和FastReID架构 对于模型架构、损失函数、实验…

进程间通信 管道

前言 ubuntu系统的默认用户名不为root的解决方案(但是不建议):轻量应用服务器 常见问题-文档中心-腾讯云 (tencent.com) 进程间通信的基本概念 进程间通信目的:进程间也是需要协同的,比如数据传输、资源共享、通知事件…