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

相关文章

使用Dify访问mysql数据库详细代码示例

《使用Dify访问mysql数据库详细代码示例》:本文主要介绍使用Dify访问mysql数据库的相关资料,并详细讲解了如何在本地搭建数据库访问服务,使用ngrok暴露到公网,并创建知识库、数据库访... 1、在本地搭建数据库访问的服务,并使用ngrok暴露到公网。#sql_tools.pyfrom

使用mvn deploy命令上传jar包的实现

《使用mvndeploy命令上传jar包的实现》本文介绍了使用mvndeploy:deploy-file命令将本地仓库中的JAR包重新发布到Maven私服,文中通过示例代码介绍的非常详细,对大家的学... 目录一、背景二、环境三、配置nexus上传账号四、执行deploy命令上传包1. 首先需要把本地仓中要

Windows系统下如何查找JDK的安装路径

《Windows系统下如何查找JDK的安装路径》:本文主要介绍Windows系统下如何查找JDK的安装路径,文中介绍了三种方法,分别是通过命令行检查、使用verbose选项查找jre目录、以及查看... 目录一、确认是否安装了JDK二、查找路径三、另外一种方式如果很久之前安装了JDK,或者在别人的电脑上,想

Spring Cloud之注册中心Nacos的使用详解

《SpringCloud之注册中心Nacos的使用详解》本文介绍SpringCloudAlibaba中的Nacos组件,对比了Nacos与Eureka的区别,展示了如何在项目中引入SpringClo... 目录Naacos服务注册/服务发现引⼊Spring Cloud Alibaba依赖引入Naco编程s依

Java springBoot初步使用websocket的代码示例

《JavaspringBoot初步使用websocket的代码示例》:本文主要介绍JavaspringBoot初步使用websocket的相关资料,WebSocket是一种实现实时双向通信的协... 目录一、什么是websocket二、依赖坐标地址1.springBoot父级依赖2.springBoot依赖

Java使用Mail构建邮件功能的完整指南

《Java使用Mail构建邮件功能的完整指南》JavaMailAPI是一个功能强大的工具,它可以帮助开发者轻松实现邮件的发送与接收功能,本文将介绍如何使用JavaMail发送和接收邮件,希望对大家有所... 目录1、简述2、主要特点3、发送样例3.1 发送纯文本邮件3.2 发送 html 邮件3.3 发送带

Windows命令之tasklist命令用法详解(Windows查看进程)

《Windows命令之tasklist命令用法详解(Windows查看进程)》tasklist命令显示本地计算机或远程计算机上当前正在运行的进程列表,命令结合筛选器一起使用,可以按照我们的需求进行过滤... 目录命令帮助1、基本使用2、执行原理2.1、tasklist命令无法使用3、筛选器3.1、根据PID

使用DeepSeek搭建个人知识库(在笔记本电脑上)

《使用DeepSeek搭建个人知识库(在笔记本电脑上)》本文介绍了如何在笔记本电脑上使用DeepSeek和开源工具搭建个人知识库,通过安装DeepSeek和RAGFlow,并使用CherryStudi... 目录部署环境软件清单安装DeepSeek安装Cherry Studio安装RAGFlow设置知识库总

Python FastAPI入门安装使用

《PythonFastAPI入门安装使用》FastAPI是一个现代、快速的PythonWeb框架,用于构建API,它基于Python3.6+的类型提示特性,使得代码更加简洁且易于绶护,这篇文章主要介... 目录第一节:FastAPI入门一、FastAPI框架介绍什么是ASGI服务(WSGI)二、FastAP

Spring-AOP-ProceedingJoinPoint的使用详解

《Spring-AOP-ProceedingJoinPoint的使用详解》:本文主要介绍Spring-AOP-ProceedingJoinPoint的使用方式,具有很好的参考价值,希望对大家有所帮... 目录ProceedingJoinPoijsnt简介获取环绕通知方法的相关信息1.proceed()2.g