为什么 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

相关文章

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

python使用try函数详解

《python使用try函数详解》Pythontry语句用于异常处理,支持捕获特定/多种异常、else/final子句确保资源释放,结合with语句自动清理,可自定义异常及嵌套结构,灵活应对错误场景... 目录try 函数的基本语法捕获特定异常捕获多个异常使用 else 子句使用 finally 子句捕获所

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali