zoukankan      html  css  js  c++  java
  • 实现 Win32 程序的消息映射宏(类似 MFC )

      对于消息映射宏,不用多说了,用过 MFC 的人都很清楚。但目前有不少程序由于各种原因并没有使用 MFC,所以本帖讨论一下如何在 Win32 程序中实现类似MFC的消息映射宏。其实 Windows 的头文件 “WindowsX.h”(注意:不是“Windows.h”) 中提供了一些有用的宏来帮助我们实现消息映射。本座是也基于这个头文件实现消息映射,首先看看宏定义文件:

    复制代码
    #pragma once

    #include <windowsx.h>

    /************************************************************************/
    /* 消息映射帮助宏 */
    /************************************************************************/

    /* see: WindowsX.h */
    #define HANDLE_SYS_MSG(hwnd, message, fn) HANDLE_MSG(hwnd, message, fn)

    /* LRESULT Cls_OnMessage(HWND hwnd, WPARAM wParam, LPARAM lParam) */
    #define HANDLE_USER_MSG(hwnd, message, fn)
    case (message): return (LRESULT)(fn)((hwnd), (wParam), (lParam))

    #define FORWARD_USER_MSG(hwnd, message, wParam, lParam, fn)
    (LRESULT)(fn)((hwnd), (message), (wParam), (lParam))

    #define GET_WND_PROC_INTERNAL(theClass, flag) ((WNDPROC)theClass##flag##WndProc)
    #define GET_DLG_PROC_INTERNAL(theClass, flag) ((DLGPROC)theClass##flag##DlgProc)

    #define DECLARE_MSG_MAP_INTERNAL(theClass, flag)
    static LRESULT CALLBACK theClass##flag##WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

    #define DECLARE_DLG_MSG_MAP_INTERNAL(theClass, flag)
    static BOOL CALLBACK theClass##flag##DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

    #define BEGIN_MSG_MAP_INTERNAL(theClass, flag)
    LRESULT theClass##flag##WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    LRESULT result = 0;

    switch(msg)
    {

    #define BEGIN_DLG_MSG_MAP_INTERNAL(theClass, flag)
    BOOL theClass##flag##DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    BOOL retVal = TRUE;
    LRESULT result = 0;

    switch(msg)
    {

    // 窗口过程为类中的静态成员函数
    #define GET_WND_PROC(theClass) GET_WND_PROC_INTERNAL(theClass, ::)
    #define GET_DLG_PROC(theClass) GET_DLG_PROC_INTERNAL(theClass, ::)

    #define DECLARE_MSG_MAP(theClass)
    public:
    DECLARE_MSG_MAP_INTERNAL(theClass, ::)

    #define DECLARE_DLG_MSG_MAP(theClass)
    public:
    DECLARE_DLG_MSG_MAP_INTERNAL(theClass, ::)

    #define BEGIN_MSG_MAP(theClass) BEGIN_MSG_MAP_INTERNAL(theClass, ::)
    #define BEGIN_DLG_MSG_MAP(theClass) BEGIN_DLG_MSG_MAP_INTERNAL(theClass, ::)

    /* 消息处理函数的声明请参考: <WindowsX.h> 的 HANDLE_MSG */
    #define ADD_MSG_MAP(msg, fn)
    case (msg): result = HANDLE_##msg((hWnd), (wParam), (lParam), (fn)); break;

    /* LRESULT Cls_OnMessage(HWND hwnd, WPARAM wParam, LPARAM lParam) */
    #define ADD_USER_MSG_MAP(msg, fn)
    case (msg): result = (LRESULT)(fn)((hWnd), (wParam), (lParam)); break;

    #define END_MSG_MAP()
    default:
    result = ::DefWindowProc(hWnd, msg, wParam, lParam);
    }

    return result;
    }

    #define END_DLG_MSG_MAP()
    default:
    retVal = FALSE;
    }

    if(retVal)
    SetDlgMsgResult(hWnd, msg, result);

    return retVal;
    }

    // 窗口过程为全局函数
    #define GET_GLOBAL_WND_PROC(theClass) GET_WND_PROC_INTERNAL(theClass, _)
    #define DECLARE_GLOBAL_MSG_MAP(theClass) DECLARE_MSG_MAP_INTERNAL(theClass, _)
    #define BEGIN_GLOBAL_MSG_MAP(theClass) BEGIN_MSG_MAP_INTERNAL(theClass, _)
    #define END_GLOBAL_MSG_MAP() END_MSG_MAP()

    #define GET_GLOBAL_DLG_PROC(theClass) GET_DLG_PROC_INTERNAL(theClass, _)
    #define DECLARE_GLOBAL_DLG_MSG_MAP(theClass) DECLARE_DLG_MSG_MAP_INTERNAL(theClass, _)
    #define BEGIN_GLOBAL_DLG_MSG_MAP(theClass) BEGIN_DLG_MSG_MAP_INTERNAL(theClass, _)
    #define END_GLOBAL_DLG_MSG_MAP() END_DLG_MSG_MAP()

    // 绑定对象指针到窗口
    #define ATTACH_OBJ_PTR_TO_WINDOW(hwnd, objPtr) ::SetWindowLong(hwnd, GWL_USERDATA, (LONG_PTR)objPtr)
    #define GET_OBJ_PTR_FROM_WINDOW(hwnd, theClass) (theClass*)(LONG_PTR)::GetWindowLong(hwnd, GWL_USERDATA)

    #define DEFINE_OBJ_PTR_FROM_WINDOW(hwnd, theClass, pObj)
    theClass* pObj = (theClass*)(LONG_PTR)::GetWindowLong(hwnd, GWL_USERDATA);
    ASSERT(pObj);
    复制代码

      先介绍一下几个重要的宏定义:

    • DECLARE_MSG_MAP(theClass):声明窗口过程函数,其中窗口过程函数实现为类的静态方法
    • DECLARE_GLOBAL_MSG_MAP(theClass):声明窗口过程函数,其中窗口过程函数实现为全局函数,因此“theClass”参数可以任意写,不一定是类名
    • DECLARE_DLG_MSG_MAP(theClass):声明对话框的窗口过程函数,其中窗口过程函数实现为类的静态方法
    • DECLARE_GLOBAL_DLG_MSG_MAP(theClass):声明对话框窗口过程函数,其中窗口过程函数实现为全局函数,因此“theClass”参数可以任意写,不一定是类名
    • BEGIN_MSG_MAP(theClass):定义窗口过程函数,其中窗口过程函数实现为类的静态方法
    • BEGIN_GLOBAL_MSG_MAP(theClass):定义窗口过程函数,其中窗口过程函数实现为全局函数,因此“theClass”参数可以任意写,不一定是类名
    • BEGIN_DLG_MSG_MAP(theClass):定义对话框的窗口过程函数,其中窗口过程函数实现为类的静态方法
    • BEGIN_GLOBAL_DLG_MSG_MAP(theClass):定义对话框窗口过程函数,其中窗口过程函数实现为全局函数,因此“theClass”参数可以任意写,不一定是类名
    • ADD_MSG_MAP(msg, fn):添加 Windows 内部消息映射
    • ADD_USER_MSG_MAP(msg, fn):添加用户自定义消息映射
    • END_MSG_MAP():结束消息映射,对应 BEGIN_MSG_MAP
    • END_GLOBAL_MSG_MAP():结束消息映射,对应 BEGIN_GLOBAL_MSG_MAP
    • END_DLG_MSG_MAP():结束消息映射,对应 BEGIN_DLG_MSG_MAP
    • END_GLOBAL_DLG_MSG_MAP():结束消息映射,对应 BEGIN_GLOBAL_DLG_MSG_MAP
    • GET_WND_PROC(theClass):获取窗口过程函数的地址,对应 DECLARE_MSG_MAP
    • GET_GLOBAL_WND_PROC(theClass):获取窗口过程函数的地址,对应 DECLARE_GLOBAL_MSG_MAP
    • GET_DLG_PROC(theClass):获取对话框窗口过程函数的地址,对应 DECLARE_DLG_MSG_MAP
    • GET_GLOBAL_DLG_PROC(theClass):获取对话框窗口过程函数的地址,对应 DECLARE_GLOBAL_DLG_MSG_MAP
    • ATTACH_OBJ_PTR_TO_WINDOW(hwnd, objPtr):把对象指针与窗口句柄进行绑定
    • GET_OBJ_PTR_FROM_WINDOW(hwnd, theClass):从窗口句柄中获取对象指针
    • DEFINE_OBJ_PTR_FROM_WINDOW(hwnd, theClass, pObj):从窗口句柄中获取对象指针,并赋值给局部变量 pObj

       这里说明一下:对话框的消息映射与普通窗口的消息映射使用不同的宏进行定义;另外,窗口过程可以实现为类的静态方法或全局函数。例如,如果要定义一个对话框的窗口过程,并实现为全局函数则使用 DECLARE_GLOBAL_DLG_MSG_MAPBEGIN_GLOBAL_DLG_MSG_MAP、END_GLOBAL_DLG_MSG_MAP  GET_GLOBAL_DLG_PROC 系列宏。

      下面以一个普通窗口的消息映射为例子演示如何使用这些宏:

    复制代码
    /*** MyClass.h ***/
    class MyClass
    {
      // 其它方法
      virtual void OnDraw(const paint_dc& dc);
      virtual BOOL Destroy();
      // 系统消息
    static BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);
    static void OnDestroy(HWND hwnd);
    static void OnPaint(HWND hWnd);
    static void OnClose(HWND hwnd);
    static void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
    static void OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags);
    static void OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
    static void OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized);
      // 用户自定义消息
    static LRESULT OnLockScreen(HWND hwnd, WPARAM wParam, LPARAM lParam);
      static LRESULT OnMenuBtnDown(HWND hwnd, WPARAM wParam, LPARAM lParam);
    static LRESULT OnSensorUp(HWND hwnd, WPARAM wParam, LPARAM lParam);
    static LRESULT OnSensorDown(HWND hwnd, WPARAM wParam, LPARAM lParam);
    static LRESULT OnSensorLeft(HWND hwnd, WPARAM wParam, LPARAM lParam);
    static LRESULT OnSensorRight(HWND hwnd, WPARAM wParam, LPARAM lParam);
      // 声明窗口过程
      DECLARE_MSG_MAP(MyClass)
    };
    复制代码
    复制代码
    /*** MyClass.cpp ***/

    #include "MyClass.h"
    // 定义消息映射
    BEGIN_MSG_MAP(MyClass)
    ADD_MSG_MAP(WM_CREATE, OnCreate)
    ADD_MSG_MAP(WM_CLOSE, OnClose)
    ADD_MSG_MAP(WM_DESTROY, OnDestroy)
    ADD_MSG_MAP(WM_PAINT, OnPaint)
    ADD_MSG_MAP(WM_LBUTTONDOWN, OnLButtonDown)
    ADD_MSG_MAP(WM_LBUTTONUP, OnLButtonUp)
    ADD_MSG_MAP(WM_MOUSEMOVE, OnMouseMove)
    ADD_MSG_MAP(WM_ACTIVATE, OnActivate)
    ADD_USER_MSG_MAP(MSG_MENU_BTN_DOWN, OnMenuBtnDown)
    ADD_USER_MSG_MAP(MSG_SENSOR_UP, OnSensorUp)
    ADD_USER_MSG_MAP(MSG_SENSOR_DOWN, OnSensorDown)
    ADD_USER_MSG_MAP(MSG_SENSOR_LEFT, OnSensorLeft)
    ADD_USER_MSG_MAP(MSG_SENSOR_RIGHT, OnSensorRight)
    ADD_USER_MSG_MAP(SHELL_MSG_LOCK_SCREEN, OnLockScreen)
    END_MSG_MAP()
    // 实现消息处理函数
    BOOL MyClass::OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
    {
      // 把 lpCreateStruct->lpCreateParams 绑定到 hwnd。
      // 通常 lpCreateStruct->lpCreateParams 设置 MyClass 对象的 this 指针,在 ::CreateWindowEx() 函数中指定。
    ATTACH_OBJ_PTR_TO_WINDOW(hwnd, lpCreateStruct->lpCreateParams);

    return TRUE;
    }

    void MyClass::OnClose(HWND hwnd)
    {
      // 获取 hwnd 绑定的对象指针,并赋值给局部变量 pvShell
    DEFINE_OBJ_PTR_FROM_WINDOW(hwnd, MyClass, pvShell);

    pvShell->Destroy();
    }

    void MyClass::OnDestroy(HWND hwnd)
    {
    ::PostQuitMessage(0);
    }

    void MyClass::OnPaint(HWND hwnd)
    {
      // 获取 hwnd 绑定的对象指针,并赋值给局部变量 pvShell 
    DEFINE_OBJ_PTR_FROM_WINDOW(hwnd, MyClass, pvShell);

    paint_dc dc(hwnd);
    pvShell->OnDraw(dc);
    }

    void MyClass::OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
    {
    // ...
    }

    void MyClass::OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
    {
    // ...
    }

    // 其它消息处理方法
    // 。。。。。。
    复制代码


      重要说明:不知大家是否注意到,我们的消息处理函数与 MFC 的消息处理函数是有区别的。区别就在于我们的消息处理函数是 static 类型的,而 MFC 的消息处理函数则不是。因此,MFC 的消息处理函数很容易获得 this 指针,而我们的函数就没那么直接了,因此需要使用了比较迂回的方法获取 this 指针,具体方法是:

      1. 在 ::CreateWindowEx(... , lpParam) 方法中,把 MyClass 的 this 指针作为参数传入。
      2.  处理 WM_CREATE 消息时调用 ATTACH_OBJ_PTR_TO_WINDOW(hwnd, lpCreateStruct->lpCreateParams),把 this 指针绑定到 hwnd。
      3. 在其他消息处理方法中用 GET_OBJ_PTR_FROM_WINDOW 或 DEFINE_OBJ_PTR_FROM_WINDOW 获取 this 指针。

    转自:http://www.cnblogs.com/ldcsaa/archive/2012/02/13/2348588.html

  • 相关阅读:
    Activity 之使用
    Activity 之生命周期
    Activity 关于生命周期一些问题的实践验证
    深入理解Java虚拟机-第1章-走进Java-读书笔记
    代码整洁之道-第11章-系统-读书笔记
    代码整洁之道-第10章-类-读书笔记
    代码整洁之道-第9章-单元测试-读书笔记
    代码整洁之道-第8章-边界-读书笔记
    代码整洁之道-第7章-错误处理-读书笔记
    华为交换机做端口流量统计
  • 原文地址:https://www.cnblogs.com/Dageking/p/3368429.html
Copyright © 2011-2022 走看看