为什么 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 两个成员,分别表示鼠标光标的水平和垂直位置(以屏幕坐标表示)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值