为什么 Windows API 选择使用 WPARAM 而不是直接使用 UINT

2024-08-25 13:12

本文主要是介绍为什么 Windows API 选择使用 WPARAM 而不是直接使用 UINT,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

WPARAM 实际上是 UINT 的别名,或者更准确地说,它的定义与 UINT 相同。在 Windows API 中,WPARAMUINT 通常是等价的,它们都表示无符号的整数类型。为什么 Windows API 选择使用 WPARAM 而不是直接使用 UINT,主要有以下几个原因:

1. 语义明确性

  • 目的明确: 使用 WPARAM 可以明确表示某个参数的用途或意义。例如,当你看到 WPARAM 类型的参数时,立刻知道它是用于传递消息相关的信息,而不是任意的整数值。这样可以帮助开发者理解和维护代码,确保消息处理代码的意图清晰。

  • 一致性: Windows API 中使用了多个不同的类型(如 WPARAMLPARAMLRESULT)来表示不同的消息参数和返回值。这样的设计使得代码中不同参数的角色更加明确。虽然 WPARAMUINT 在底层上是相同的,但 WPARAM 提供了一种更具体的语义标记。

2. API 设计的历史

  • 历史原因: Windows API 的设计有很强的历史背景。在 Windows 早期版本中,WPARAMLPARAM 是用来处理消息的设计中包含的类型。这些类型的使用可能源于早期的设计决策,并且逐渐成为了 API 的标准做法。

  • 兼容性: 由于 Windows API 的成熟和广泛使用,改变现有的类型定义会导致兼容性问题。为了确保向后兼容,Windows API 保持了 WPARAMLPARAM 等类型,即使在技术上它们可能与 UINTLONG 等基本类型等价。

3. 代码文档和阅读

  • 文档和阅读: 使用 WPARAM 而不是 UINT 可以帮助开发者更容易地理解代码和文档。在处理消息时,WPARAMLPARAM 的使用可以明确表示这两个参数的不同作用(例如,WPARAM 用于表示消息的附加数据,而 LPARAM 可以用于存储更复杂的数据)。

  • 上下文感知: 当看到 WPARAMLPARAM 时,开发者可以立即识别这些参数是消息处理的特殊类型,而不仅仅是整数值。这种上下文感知可以提高代码的可读性和维护性。

4. 标准化

  • 标准化: Windows API 使用 WPARAM 和 LPARAM 是一种标准化做法,确保了 API 的一致性和可预测性。标准化的数据类型有助于确保不同组件和模块之间的一致性,减少误用的可能性。

综上所述,WPARAMUINT 在底层上可能是等价的,但 WPARAM 的使用提供了更明确的语义和一致性,这在大型 API 设计和维护中是非常重要的。

-------------------

WPARAM 是 Windows API 中定义的一个数据类型,主要用于消息传递机制。以下是对 WPARAM 的详细解释:

定义与类型

  • 定义: WPARAM 是一个无符号的整数类型,用于表示消息处理过程中的参数。它通常用于传递附加的数据或状态信息。

  • 类型: 在 Windows API 中,WPARAM 被定义为 UINT,这意味着它实际上是一个 unsigned int 类型。在不同的 Windows 平台和编译器中,UINT 的大小可能有所不同,但通常是 32 位的。

作用与用法

  • 消息处理: WPARAM 通常用于消息处理函数(例如 WndProc)中的参数之一,用于传递与消息相关的附加信息。比如,WM_LBUTTONDOWN 消息中的 WPARAM 可能包含鼠标的状态信息,如是否按住了 Shift 键。

  • 函数签名: 在处理 Windows 消息的回调函数(如 WndProc)时,WPARAM 通常作为 wParam 参数传递。函数签名类似于:

    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

    在这个函数中,wParam 就是 WPARAM 类型的参数。

示例

以下是一个处理鼠标点击消息的例子,其中 WPARAM 用于检查鼠标的状态:

#include <windows.h>LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {switch (msg) {case WM_LBUTTONDOWN:if (wParam & MK_SHIFT) {// Shift 键也被按下MessageBox(hwnd, "Shift key is pressed.", "Information", MB_OK);} else {// 只有鼠标左键被按下MessageBox(hwnd, "Left mouse button is pressed.", "Information", MB_OK);}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, msg, wParam, lParam);}return 0;
}int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {const char CLASS_NAME[] = "Sample Window Class";WNDCLASS wc = {};wc.lpfnWndProc = WndProc;wc.hInstance = hInstance;wc.lpszClassName = CLASS_NAME;RegisterClass(&wc);HWND hwnd = CreateWindowEx(0,CLASS_NAME,"Sample Window",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL,hInstance,NULL);if (hwnd == NULL) {return 0;}ShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd);MSG msg;while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}

总结

  • 数据类型WPARAM 是一个无符号整数类型,通常被定义为 UINT
  • 用途: 用于传递与消息相关的附加信息或状态。
  • 上下文: 主要用于 Windows 消息处理的回调函数中,帮助识别消息的细节或状态信息。

WPARAM 的使用帮助提高了 Windows API 消息处理的灵活性和功能性。

---------------------

LRESULT 是 Windows API 中用于消息处理的返回值类型。它代表一个可能返回的结果或状态值,通常用在消息处理函数(如 WndProc)中。以下是 LRESULT 的一些关键点:

定义与类型

  • 定义: LRESULT 是一个数据类型,用于函数的返回值,表示消息处理的结果。它的定义可以依据平台和编译器而有所不同。

  • 类型: 在 32 位系统中,LRESULT 通常被定义为 LONG_PTR,在 64 位系统中,LRESULT 则是 LONG_PTRLRESULT。基本上,它可以是一个 LONGLONG_PTR,具体取决于平台的位数。

作用与用法

  • 消息处理返回值: 在消息处理函数中,LRESULT 返回值用于指示消息的处理结果。例如,在 WndProc 函数中,返回值可以是特定的结果代码或状态。

  • 函数签名: LRESULT 通常作为消息处理函数的返回值,例如:

    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

    在这个函数中,LRESULT 用于返回消息处理的结果。

示例

以下是一个 WndProc 函数的例子,其中 LRESULT 用于返回处理结果:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {switch (msg) {case WM_PAINT:// 处理绘制消息{PAINTSTRUCT ps;HDC hdc = BeginPaint(hwnd, &ps);// 绘制代码EndPaint(hwnd, &ps);}return 0; // 表示消息已处理case WM_DESTROY:PostQuitMessage(0);return 0; // 表示消息已处理default:return DefWindowProc(hwnd, msg, wParam, lParam); // 处理未处理的消息}
}

总结

  • 数据类型LRESULT 用于表示消息处理函数的返回值,通常是 LONG 或 LONG_PTR
  • 用途: 表示处理结果或状态,在消息处理函数中返回。
  • 上下文: 主要用于 Windows 消息处理的回调函数中,以便在处理完成后返回适当的结果或状态。

--------------

LONG_PTR 是 Windows API 中用于处理长整型指针的一个数据类型,它提供了一种平台无关的方式来处理指针或长整型数据。以下是 LONG_PTR 的一些关键点:

定义与类型

  • 定义: LONG_PTR 是一个宏定义,它的具体定义依赖于平台的位数。它通常用于确保在不同的位数系统中,指针大小的一致性和兼容性。

  • 类型: 在 32 位系统中,LONG_PTR 通常定义为 LONG,在 64 位系统中,LONG_PTR 通常定义为 __int64。这样可以确保在 32 位和 64 位系统中都能正确地处理指针或长整型数据。

    typedef __int64 LONG_PTR; // 在 64 位系统中 typedef long LONG_PTR; // 在 32 位系统中

作用与用法

  • 平台无关: LONG_PTR 主要用于处理可能需要指针大小的整型值,如在 Windows API 中传递指针或长整型数据。它确保了数据在不同位数系统中的一致性。

  • 消息处理: 在消息处理函数中,LONG_PTR 可能被用作消息参数,例如 lParam 参数,它可以包含指针或长整型数据。

  • WPARAMLPARAM 相关: LONG_PTRWPARAMLPARAM 类型密切相关。LPARAM 用于传递长整型数据或指针,LONG_PTR 确保了 LPARAM 的类型在不同位数的系统中都是正确的。

示例

以下是一个示例,展示了如何使用 LONG_PTR 来处理窗口消息中的长整型数据:

#include <windows.h>
#include <stdio.h>// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {switch (msg) {case WM_LBUTTONDOWN: { // 处理左键点击int xPos = LOWORD(lParam);  // 获取鼠标x坐标int yPos = HIWORD(lParam);  // 获取鼠标y坐标char buf[100];snprintf(buf, sizeof(buf), "Left button clicked at (%d, %d)", xPos, yPos);SetWindowText(hwnd, buf);  // 更新窗口标题栏为点击位置break;}case WM_RBUTTONDOWN: { // 处理右键点击int xPos = LOWORD(lParam);  // 获取鼠标x坐标int yPos = HIWORD(lParam);  // 获取鼠标y坐标char buf[100];snprintf(buf, sizeof(buf), "Right button clicked at (%d, %d)", xPos, yPos);SetWindowText(hwnd, buf);  // 更新窗口标题栏为点击位置break;}case WM_MOUSEMOVE: { // 处理鼠标移动int xPos = LOWORD(lParam);  // 获取鼠标x坐标int yPos = HIWORD(lParam);  // 获取鼠标y坐标char buf[100];snprintf(buf, sizeof(buf), "Mouse moved to (%d, %d)", xPos, yPos);SetWindowText(hwnd, buf);  // 更新窗口标题栏为鼠标移动位置break;}case WM_DESTROY:PostQuitMessage(0); // 退出消息循环break;default:return DefWindowProc(hwnd, msg, wParam, lParam); // 默认窗口过程}return 0;
}// 程序入口
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {const char CLASS_NAME[] = "Sample Window Class";// 定义窗口类WNDCLASS wc = {};wc.lpfnWndProc = WndProc;wc.hInstance = hInstance;wc.lpszClassName = CLASS_NAME;wc.hCursor = LoadCursor(NULL, IDC_ARROW);  // 设置光标// 注册窗口类if (!RegisterClass(&wc)) {MessageBox(NULL, "Window Class Registration Failed!", "Error", MB_OK | MB_ICONERROR);return 0;}// 创建窗口HWND hwnd = CreateWindowEx(0,                              // 可选窗口样式CLASS_NAME,                     // 窗口类名"Sample Window",                // 窗口标题WS_OVERLAPPEDWINDOW,            // 窗口样式CW_USEDEFAULT, CW_USEDEFAULT,   // 初始位置CW_USEDEFAULT, CW_USEDEFAULT,   // 初始尺寸NULL,                           // 父窗口NULL,                           // 菜单hInstance,                      // 实例句柄NULL                            // 附加应用程序数据);if (hwnd == NULL) {MessageBox(NULL, "Window Creation Failed!", "Error", MB_OK | MB_ICONERROR);return 0;}// 显示窗口ShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd);// 消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}
#include <windows.h>
#include <stdio.h>#define IDC_STATIC_TEXT 1001 // 控件ID// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {static HWND hStatic; // 静态控件句柄switch (msg) {case WM_CREATE: {// 创建静态控件hStatic = CreateWindow("STATIC",          // 控件类名"",                // 控件初始文本WS_CHILD | WS_VISIBLE | SS_LEFT, // 控件样式50, 60, 300, 20,   // 位置和大小hwnd,              // 父窗口句柄(HMENU)IDC_STATIC_TEXT, // 控件ID((LPCREATESTRUCT)lParam)->hInstance, // 实例句柄NULL               // 附加应用程序数据);if (hStatic == NULL) {MessageBox(hwnd, "Failed to create static control!", "Error", MB_OK | MB_ICONERROR);return -1; // 创建失败,退出消息循环}break;}case WM_LBUTTONDOWN: { // 处理左键点击事件int xPos = LOWORD(lParam);  // 获取鼠标x坐标int yPos = HIWORD(lParam);  // 获取鼠标y坐标char buf[100];snprintf(buf, sizeof(buf), "Left button clicked at (%d, %d)", xPos, yPos);SetWindowText(hStatic, buf);  // 更新静态控件文本break;}case WM_RBUTTONDOWN: { // 处理右键点击事件int xPos = LOWORD(lParam);  // 获取鼠标x坐标int yPos = HIWORD(lParam);  // 获取鼠标y坐标char buf[100];snprintf(buf, sizeof(buf), "Right button clicked at (%d, %d)", xPos, yPos);SetWindowText(hStatic, buf);  // 更新静态控件文本break;}case WM_MOUSEMOVE: { // 处理鼠标移动事件int xPos = LOWORD(lParam);  // 获取鼠标x坐标int yPos = HIWORD(lParam);  // 获取鼠标y坐标char buf[100];snprintf(buf, sizeof(buf), "Mouse moved to (%d, %d)", xPos, yPos);SetWindowText(hStatic, buf);  // 更新静态控件文本break;}case WM_DESTROY:PostQuitMessage(0); // 退出消息循环break;default:return DefWindowProc(hwnd, msg, wParam, lParam); // 默认窗口过程}return 0;
}// 程序入口
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {const char CLASS_NAME[] = "Sample Window Class";// 定义窗口类WNDCLASS wc = {};wc.lpfnWndProc = WndProc;          // 窗口过程函数wc.hInstance = hInstance;          // 实例句柄wc.lpszClassName = CLASS_NAME;     // 窗口类名wc.hCursor = LoadCursor(NULL, IDC_ARROW);  // 设置光标// 注册窗口类if (!RegisterClass(&wc)) {MessageBox(NULL, "Window Class Registration Failed!", "Error", MB_OK | MB_ICONERROR);return 0;}// 创建窗口HWND hwnd = CreateWindowEx(0,                              // 可选窗口样式CLASS_NAME,                     // 窗口类名"Sample Window",                // 窗口标题WS_OVERLAPPEDWINDOW,            // 窗口样式CW_USEDEFAULT, CW_USEDEFAULT,   // 初始位置CW_USEDEFAULT, CW_USEDEFAULT,   // 初始尺寸NULL,                           // 父窗口NULL,                           // 菜单hInstance,                      // 实例句柄NULL                            // 附加应用程序数据);if (hwnd == NULL) {MessageBox(NULL, "Window Creation Failed!", "Error", MB_OK | MB_ICONERROR);return 0;}// 显示窗口ShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd);// 消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}

总结

  • 数据类型LONG_PTR 是用于处理指针大小的长整型数据类型,确保在 32 位和 64 位系统中一致性。
  • 用途: 主要用于 Windows API 的消息处理,确保指针或长整型数据在不同系统中的兼容性。
  • 上下文: 在处理涉及指针或长整型数据的 Windows 消息时使用,确保数据在各种平台上的正确处理。

------------

MSG 结构体是 Windows API 中用于处理消息的基本数据结构。它包含了从系统消息队列中获取的关于特定事件的信息,例如键盘输入、鼠标动作、窗口调整大小、系统命令等。通过 MSG 结构体,Windows 应用程序可以识别并响应这些事件。

MSG 结构体的定义

在 Windows API 中,MSG 结构体定义如下:

typedef struct tagMSG {HWND   hwnd;     // 消息目标窗口的句柄UINT   message;  // 消息的类型(例如 WM_PAINT, WM_KEYDOWN)WPARAM wParam;   // 附加的消息特定信息(例如键盘按键的虚拟键码)LPARAM lParam;   // 附加的消息特定信息(例如鼠标坐标)DWORD  time;     // 消息被发布的时间戳POINT  pt;       // 消息发生时的鼠标光标位置
} MSG, *PMSG;

MSG 结构体的成员详解

  1. HWND hwnd:

    • 类型:HWND(窗口句柄)
    • 描述:指定了接收消息的窗口的句柄。如果消息不涉及特定窗口,则该值可能为 NULL
  2. UINT message:

    • 类型:UINT(无符号整数)
    • 描述:消息的类型,通常以 WM_ 前缀命名。例如,WM_PAINT 表示需要重绘窗口,WM_KEYDOWN 表示某个键被按下。Windows 定义了大量的消息类型,每种类型都有其特定的含义和用途。
  3. WPARAM wParam:

    • 类型:WPARAM(与操作系统位数相关的无符号整数)
    • 描述:包含有关消息的附加信息。具体含义取决于消息的类型。例如,在 WM_KEYDOWN 消息中,wParam 表示被按下的虚拟键码。
  4. LPARAM lParam:

    • 类型:LPARAM(与操作系统位数相关的有符号长整数)
    • 描述:包含有关消息的附加信息,类似于 wParam,其含义也取决于消息类型。例如,在鼠标移动消息 WM_MOUSEMOVE 中,lParam 包含了鼠标的 x 和 y 坐标。
  5. DWORD time:

    • 类型:DWORD(双字,无符号整数)
    • 描述:表示消息被发布的时间戳,单位是毫秒。它通常用来确定事件的顺序。
  6. POINT pt:

    • 类型:POINT 结构体
    • 描述:表示消息发生时鼠标光标的位置。POINT 结构体包含 xy 两个成员,分别表示鼠标光标的水平和垂直位置(以屏幕坐标表示)。

这篇关于为什么 Windows API 选择使用 WPARAM 而不是直接使用 UINT的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1105651

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

如何选择适合孤独症兄妹的学校?

在探索适合孤独症儿童教育的道路上,每一位家长都面临着前所未有的挑战与抉择。当这份责任落在拥有孤独症兄妹的家庭肩上时,选择一所能够同时满足两个孩子特殊需求的学校,更显得尤为关键。本文将探讨如何为这样的家庭做出明智的选择,并介绍星贝育园自闭症儿童寄宿制学校作为一个值得考虑的选项。 理解孤独症儿童的独特性 孤独症,这一复杂的神经发育障碍,影响着儿童的社交互动、沟通能力以及行为模式。对于拥有孤独症兄

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验