对于消息映射宏,不用多说了,用过 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 指针。

CodeProject

转载于:https://www.cnblogs.com/ldcsaa/archive/2012/02/13/2348588.html

实现 Win32 程序的消息映射宏(类似 MFC )相关推荐

  1. MFC 教程【4_消息映射的实现】

    消息映射的实现 Windows消息概述 Windows应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口.这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows. 消息的 ...

  2. 【转】MFC消息映射详解(整理转载)

    消息:主要指由用户操作而向应用程序发出的信息,也包括操作系统内部产生的消息.例如,单击鼠标左按钮,windows将产WM_LBUTTONDOWN消息,而释放鼠标左按钮将产生WM_LBUTTONUP消息 ...

  3. MFC消息映射的定义

    2019独角兽企业重金招聘Python工程师标准>>> BEGIN_MESSAGE_MAP( theClass, baseClass ) Parameters theClass Sp ...

  4. 【MFC】MFC消息映射(二)

    00. 目录 文章目录 00. 目录 01. 概述 02. 消息映射宏 2.1 BEGIN_MESSAGE_MAP 2.2 DECLARE_MESSAGE_MAP 2.3 END_MESSAGE_MA ...

  5. MFC六大核心机制之五、六:消息映射和命令传递

    作为C++程序员,我们总是希望自己程序的所有代码都是自己写出来的,如果使用了其他的一些库,也总是千方百计想弄清楚其中的类和函数的原理,否则就会感觉不踏实.所以,我们对于在进行MFC视窗程序设计时经常要 ...

  6. MFc消息映射机制理解

    何谓消息.消息处理函数.消息映射? 消息简单的说就是指通过输入设备向程序发出指令要执行某个操作.具体的某个操作是你的一系列代码.称为消息处理函数.在SDK中消息其实非常容易理解,当窗口建立后便会有一个 ...

  7. Windows消息映射及消息发送(SendMess、PostMess)实现

    最近在看linux系统书籍看到消息调度方面,便动手封装一个类似MFC简易的消息发送框架(参考实例,没有窗口句柄). 关于框架设计的几点介绍:     1.设计采用了自动释放消息节点方式(增加虚析构函数 ...

  8. 【MFC】MFC消息映射

    00. 目录 文章目录 00. 目录 01. 概述 02. 消息映射宏 2.1 BEGIN_MESSAGE_MAP 2.2 DECLARE_MESSAGE_MAP 2.3 END_MESSAGE_MA ...

  9. 转MFC消息映射梳理

    http://blog.csdn.net/phunxm/article/details/5640766 一.CWnd消息处理 一切从窗口(HWND)的创建说起,在MFC中,CWnd::CreateEx ...

最新文章

  1. APUE 学习笔记(一) Unix基础知识
  2. mysql 8重置root密码_如何在MySQL 8中重置root密码
  3. java 批量为图片添加图标水印和文字水印
  4. php tp5清空数据表并主键,tp5数据库——更新数据
  5. 剑指offer-JZ9 用两个栈实现队列(C++,附思路)
  6. 左手自研,右手开源,技术解读华为云如何领跑容器市场
  7. EC++学习笔记(四) 设计与声明
  8. ios网络编程(二)之网络连接
  9. linux扩容系统盘分区,系统盘扩容 扩展分区与文件系统_Linux系统盘
  10. Rhino入门教程---渐消面
  11. postgresql添加postgis拓展模块
  12. jdk工具keytool和jarsigner帮助(jdk keytooljarsigner tool manual)
  13. 计算流体动力学软件和服务市场现状研究分析-
  14. MATLAB启动慢解决方案
  15. 邮箱邮件安全问题有哪些?如何做邮件安全宣传?
  16. 江湖上再也没有摩拜单车了
  17. React之Redux
  18. Qt开发技术:QCharts(三)QCharts样条曲线图介绍、Demo以及代码详解
  19. 单元测试:通过读取csv/xml数据并且结合使用allure展示测试报告,验证开发中的add()和reduct()操作(在@allure.story分别实现相加减)
  20. 25.Linux系统忘记登录密码解决办法(别着急,还能抢救一下)

热门文章

  1. webpack 热加载你站住,我对你好奇很久了
  2. 负载均衡研究 基础
  3. db2的bufferpool不足报错的快速解决
  4. 通用的“关于本软件”对话框
  5. 实现一个Ajax模式的文件上传功能有多难?
  6. 基于DDD的golang实现
  7. Linux中断一网打尽(2) - IDT及中断处理的实现
  8. influxDB集群模式实践
  9. Java消息中间件--ActiveMq,RabbitMQ,Kafka
  10. PHP好玩的代码一(笛卡尔的情书)