翻译《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.mzph.cn/diannao/9615.shtml

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

相关文章

Django 静态文件管理与部署指南

title: Django 静态文件管理与部署指南 date: 2024/5/10 17:38:36 updated: 2024/5/10 17:38:36 categories: 后端开发 tags: WebOptCDN加速DjangoCompressWebpackStaticDeployCICD-ToolsSecStatic 第一章:介绍 Django 静态文件的概念和重要性 在 Web 开发中&a…

Linux diff命令(比较两个文件或目录的内容差异)

文章目录 Linux diff 命令详解教程基本用法比较文件输出解释 递归比较(-r)示例代码 控制输出格式统一格式(-u)上下文格式(-c) 高级选项忽略所有空白差异(-w)仅报告文件是否不同 Linu…

纯 CSS 实现标签自动显示超出数量

现代 CSS 强大的令人难以置信。 这次我们来用 CSS 实现这样一个功能:有多个宽度不同的标签水平排列,当外层宽度不足时,会提示超出的数量,演示效果如下 如果让我用 JavaScript来实现估计都有点折腾,毕竟宽度都是动态的…

有什么方便实用的黏土特效教程?6个软件教你快速进行特效制作

有什么方便实用的黏土特效教程?6个软件教你快速进行特效制作 作为时尚小达人,你自己是否想要制作出属于自己的黏土特效照片呢?比如下面几种。 看到这些黏土特效软件有没有心动,下面我也为大家详细的介绍一下可以制作出对应特效的…

Java 集合-List

集合主要分为两组(单列集合, 双列集合) Connection 接口有两个重要的子接口LIst 和 Set, 它们的实现子类都是单列集合, Map 接口的实现子类是双列集合, 存放的是 K-V Connection 接口 Collection 接口和常用方法 下面以 ArrayList 演示一下 add: 添加单个元素remove: 删除指…

Socket学习记录

本次学习Socket的编程开发,该技术在一些通讯软件,比如说微信,QQ等有广泛应用。 网络结构 这些都是计算机网络中的内容,我们在这里简单回顾一下: UDP(User Datagram Protocol):用户数据报协议;TCP(Transmission Contr…

这是一关于DSC相关的文档

这是一关于DSC相关的文档 上面这幅图清晰的展示了somewhat flat的像素图示

机器学习算法应用——关联规则分析(4-4)

关联规则分析(4-4) 关联规则分析(Association Rule Mining)是一种基于频繁项集的分析方法,它以最常出现在一起的元素之间的关系作为分析对象,主要用于发掘大数据中隐藏的关联规则,是数据挖掘技术…

小众行业风口:Q1季度擦窗机器人行业线上市场销售数据分析

今天给大家分享一个2024年的小众行业增长风口——擦窗机器人。 作为家居自动化里的重要一员,擦窗机器人可以简称为擦窗神器,是为了解决大户型家庭的外窗清洁痛点而存在。而目前,擦窗机器人行业正在走向成熟,且市场需求量居高不下…

苹果公司因iPad广告争议而道歉,承认“未达标”|TodayAI

周二,苹果公司发布了一则新的iPad Pro广告,引起了广泛争议,该公司随后发表道歉声明,承认这则广告“未达标”。这则名为“压碎!”的广告意图展示全新的M4芯片iPad Pro的创意潜力,但却因其表现方式而备受批评…

设计模式学习笔记 - 回顾总结:在实际软件开发中常用的设计思想、原则和模式

概述 本章,先来回顾下整个专栏的知识体系,主要包括面向对象、设计原则、编码规范、重构技巧、设计模式五个部分。 面向对象 相对于面向过程、函数式编程,面向对象是现在最主流的编程范式。纯面向过程的编程方法,现在已经不多见了…

浅谈如何利用 AI 提高内容生产效率?|TodayAI

在数字化时代,内容的创建和分发速度变得尤为关键。人工智能(AI)技术提供了加速这一过程的可能性,不仅提升了生产效率,还改善了内容的质量和受众的接受度。本文深入探讨AI如何在内容生成、分发与推广,以及内…

LangChain连接国内大模型测试|智谱ai、讯飞星火、通义千问

智谱AI 配置参考 https://python.langchain.com/v0.1/docs/integrations/chat/zhipuai/ZHIPUAI_API_KEY从https://open.bigmodel.cn/获取 from langchain_community.chat_models import ChatZhipuAI from langchain_core.messages import AIMessage, HumanMessage, SystemMes…

超越机械抓手:看多指机器人如何灵活运用触觉?

论文标题: Learning Visuotactile Skills with Two Multifingered Hands 论文作者: Toru Lin, Yu Zhang, Qiyang Li, Haozhi Qi, Brent Yi, Sergey Levine, and Jitendra Malik 1. 机器人新挑战:多指手指操作 在自动化和智能化日益普及的…

idea导入jar包、打jar包

一、导入jar包 1.在工程下面新建一个lib目录,将jar包放在lib目录下面 2.按步骤导入jar包 -接下来选择jar包所在的位置进行导入 -下图中标红框位置就是刚刚导入的jar包 二、直接用idea打jar包 -下图中Main Class就是选择程序中的Main函数 -右侧标红框位置表示…

VSCode Python 自动格式化代码(black)不生效

弄了很长时间,各种尝试,就想实现保存后自动格式化代码,用户设置,工作区设置,因为环境较多以为有啥冲突,就是没找到。后来看到一条评论说Python版本低,想到了版本问题。然后就看到以下描述 记录…

Spring如何控制Bean的加载顺序

前言 正常情况下,Spring 容器加载 Bean 的顺序是不确定的,那么我们如果需要按顺序加载 Bean 时应如何操作?本文将详细讲述我们如何才能控制 Bean 的加载顺序。 场景 我创建了 4 个 Class 文件,分别命名为 FirstInitialization Se…

python数据分析——数据的选择和运算

数据的选择和运算 前言一、数据选择NumPy的数据选择一维数组元素提取示例 多维数组行列选择、区域选择示例 花式索引与布尔值索引布尔索引示例一示例二 花式索引示例一示例二 Pandas数据选择Series数据获取DataFrame数据获取列索引取值示例一示例二 取行方式示例loc() 方法示例…

人脸图像生成(DCGAN)

一、理论基础 1.什么是深度卷积对抗网络(Deep Convolutional Generative Adversarial Network,) 深度卷积对抗网络(Deep Convolutional Generative Adversarial Network,DCGAN)是一种生成对抗网络&#xf…

网工内推 | 软件测试工程师,有软考中、高级认证优先

01 上海碧蔓智能科技有限公司 招聘岗位:软件测试工程师 职责描述: 1、负责软件产品的测试工作,对测试进度和测试质量负责; 2、参与业务需求、设计方案的讨论,负责编写测试方案、测试计划、测试用例,搭建测…