如何使用declare_message_map来简化消息分发?

作者:陇南麻将开发公司 阅读:36 次 发布时间:2025-05-05 00:23:40

摘要:在 Windows 程序开发过程中,窗口的消息处理是非常重要的环节之一,消息处理的代码量往往占据程序代码的很大比例。Windows 程序中,窗口消息处理的核心机制是消息分派,过多的分发代码会使程序代码变得冗长、难以维护。于是,如何简化窗口消息分发成为 Windows 程序面临的一个...

在 Windows 程序开发过程中,窗口的消息处理是非常重要的环节之一,消息处理的代码量往往占据程序代码的很大比例。Windows 程序中,窗口消息处理的核心机制是消息分派,过多的分发代码会使程序代码变得冗长、难以维护。于是,如何简化窗口消息分发成为 Windows 程序面临的一个重要问题。本文将介绍如何使用 declare_message_map 来简化消息分发。

如何使用declare_message_map来简化消息分发?

1. 消息处理基础

在 Windows 程序中,窗口消息包括系统消息和应用程序消息,如 WM_PAINT、WM_SIZE、WM_COMMAND、WM_NOTIFY 等。在实际编程中,对于每个窗口都需要编写一个窗口过程,以便接收并处理这些消息。窗口过程是一个函数,其原型为:

```C++

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

```

其中 hWnd、uMsg、wParam、lParam 分别表示窗口句柄、消息类型、消息附加参数和消息附加参数。窗口过程中需要根据不同的消息类型进行分发处理,例如:

```C++

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

switch (uMsg)

{

case WM_PAINT:

OnPaint(hWnd, wParam, lParam);

break;

case WM_SIZE:

OnSize(hWnd, wParam, lParam);

break;

case WM_COMMAND:

OnCommand(hWnd, wParam, lParam);

break;

// 其它消息类型

default:

return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

return 0;

}

```

窗口过程中的 switch 语句对不同的消息类型进行处理,每个 case 标签对应一个消息处理函数。可以看到,分发代码认为实现了消息处理的可维护性和代码结构,但随着消息种类和处理函数数量的增加,窗口过程代码将变得越来越臃肿和难以维护。

2. 使用 declare_message_map 简化消息分发

MFC 是一个非常流行的 Windows 开发框架,MFC 中的 CWnd 类提供了一个方便的机制,称为消息映射(Message Map)。使用消息映射可以避免显式的 switch 语句,大大简化了消息分发的代码。当然,我们可以不用 MFC,自己模拟一个消息映射机制。下面,我们将介绍使用 declare_message_map 来实现消息映射,声明关键字 declare_message_map 定义在头文件 afxwin.h 中。

首先,我们需要定义一个消息处理类,以封装不同消息处理函数:

```C++

class CMyWnd

{

public:

virtual ~CMyWnd() {}

virtual LRESULT OnPaint(WPARAM wParam, LPARAM lParam) { return 0; }

virtual LRESULT OnSize(WPARAM wParam, LPARAM lParam) { return 0; }

virtual LRESULT OnCommand(WPARAM wParam, LPARAM lParam) { return 0; }

// 其它消息处理函数

}

```

这是一个简单的消息处理类,并未实现任何处理函数,这里只是定义了各个消息处理函数的原型,并用虚函数声明,以方便子类进行重载,达到消息的分发目的。接下来,我们需要在窗口过程中调用消息处理类中对应的处理函数。

定义一个消息映射表,以对应窗口消息和消息处理函数之间的关系:

```C++

BEGIN_MESSAGE_MAP(CMyWnd, CWnd)

ON_WM_PAINT()

ON_WM_SIZE()

ON_WM_COMMAND()

// 其它消息类型

END_MESSAGE_MAP()

```

在这里,我们使用了宏 ON_WM_PAINT、ON_WM_SIZE、ON_WM_COMMAND 等来定义消息和消息处理函数的对应关系。这些宏被定义在 afxmsg_.h 头文件中,实际上是把消息和处理函数的关系都存储在了一个变量中,用宏 ON_MESSAGE_MAP 分行表示。

在消息映射表中,CMyWnd 是消息处理类,CWnd 是 CMyWnd 的基类,ON_WM_PAINT、ON_WM_SIZE、ON_WM_COMMAND 等是预定义的消息宏,实际上是由宏 DECLARE_MESSAGE_MAP 定义的。

这样,我们就定义了一个消息映射表,并把它和消息处理类关联起来了。接下来,我们需要在窗口过程中调用消息处理类中对应的处理函数。

```C++

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

CMyWnd* pWnd = (CMyWnd*)::GetWindowLongPtr(hWnd, GWLP_USERDATA);

if (pWnd == NULL && uMsg == WM_CREATE)

{

CREATESTRUCT* pCreateStruct = (CREATESTRUCT*)lParam;

pWnd = (CMyWnd*)pCreateStruct->lpCreateParams;

::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pWnd);

}

if (pWnd != NULL)

{

LRESULT lResult = 0;

if (pWnd->SendMessage(WM_MY_COMMAND, wParam, lParam, &lResult))

return lResult;

if (pWnd->PreTranslateMessage(hWnd, uMsg, wParam, lParam, &lResult))

return lResult;

// 处理 WM_NCDESTROY 之前需要将用户数据设置为 NULL

if (uMsg == WM_NCDESTROY)

::SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);

return pWnd->DefWindowProc(hWnd, uMsg, wParam, lParam);

}

return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

```

在窗口过程中,我们首先通过 GetWindowLongPtr 函数获取窗口数据并转换为 CMyWnd 指针,然后根据当前消息的类型,调用处理函数。

SendMessage 将消息传递给窗口的虚函数(WM_MY_COMMAND 为自定义的消息名),在这个消息里,可以进行某一事件的处理,如果消息已经处理完毕,返回LRESULT类型非0值,窗口过程根据此值不再执行默认处理。

PreTranslateMessage 是可选函数,如果想要窗口处理键盘消息需要实现此函数,否则该函数可以去掉。DefWindowProc 是默认处理函数,如果消息不能由窗口处理函数处理,则会调用 DefWindowProc。

3. 总结

使用 declare_message_map 可以大大简化消息分发的代码,增强代码的可读性和可维护性。在开发过程中,如果消息种类较多,使用消息映射机制可以显著提高代码质量和开发效率,因此建议大家尝试使用。

  • 原标题:如何使用declare_message_map来简化消息分发?

  • 本文链接:https://qipaikaifa.cn/qpzx/3991.html

  • 本文由陇南麻将开发公司中天华智网小编,整理排版发布,转载请注明出处。部分文章图片来源于网络,如有侵权,请与中天华智网联系删除。
  • 微信二维码

    ZTHZ2028

    长按复制微信号,添加好友

    微信联系

    在线咨询

    点击这里给我发消息QQ客服专员


    点击这里给我发消息电话客服专员


    在线咨询

    免费通话


    24h咨询☎️:157-1842-0347


    🔺🔺 棋牌游戏开发24H咨询电话 🔺🔺

    免费通话
    返回顶部