http://blog.csdn.net/daiyutage/article/details/17241161

Win32应用中的回调函数WndProc用于接收Windows向应用程序直接发送的消息,以及响应消息。大多情况下,我们这样编写代码:

  1. LRESULT CALLBACK WndProc(HWND hWnd,
  2. UINT message,
  3. WPARAM wParam,
  4. LPARAM lParam )
  5. {
  6. int cxClient, cyClient;
  7. PAINTSTRUCT ps;
  8. HDC hdc;
  9. switch( message )
  10. {
  11. case WM_SIZE:
  12. cxClient = LOWORD(lParam);
  13. cyClient = HIWORD(lParam);
  14. break;
  15. case WM_PAINT:
  16. hdc = BeginPaint( hWnd, &ps );
  17. EndPaint( hWnd, &ps );
  18. break;<br />
  19. case WM_DESTROY:
  20. PostQuitMessage( 0 );
  21. break;
  22. }
  23. return DefWindowProc( hWnd, message, wParam, lParam );
  24. }

这种方式通过switch分支语句分理处理各个消息,结构简单明了。但有2个问题:

  1. 在所处理的消息多了后,全部代码都集中于一个switch语句中,变量容易相互污染,且代码很长,不容易定位代码。
  2. 大多数的消息都有相应的WPARAM、LPARAM参数,但对于每个消息,其WPARAM、LPARAM参数的具体内容又不一致。就像上面WM_SIZE中的代码,我们怎么知道cyClient、cyClient的信息就放在lParam而不是wParam中,且cxClient的信息在lParam的低位,cyClient的信息在lParam的高位?我们需要随时查询SDK文档以了解这两个参数中各有什么含义,以及如何恰当地将这些参数抽取出来。不管怎样,上面的代码实际上就是个让人一团雾水的魔术代码(Magic Code).

WindowsX.h定义了许多宏,可以帮助我们解决上述这些问题。其中HANDLE_MSG宏可以大大简化Win32开发。下面我们先看使用HANDLE_MSG宏后的代码:

  1. void OnSize(HWND hwnd, UINT state, int cx, int cy)
  2. {
  3. }
  4. void OnPaint(HWND hWnd)
  5. {
  6. PAINTSTRUCT ps;
  7. HDC hdc;
  8. hdc = BeginPaint( hWnd, &ps );
  9. EndPaint( hWnd, &ps );
  10. }
  11. void OnWinDestroy(HWND hWnd)
  12. {
  13. PostQuitMessage(0);
  14. }
  15. LRESULT CALLBACK WndProc(HWND hWnd,
  16. UINT message,
  17. WPARAM wParam,
  18. LPARAM lParam )
  19. {
  20. switch( message )
  21. {
  22. HANDLE_MSG(hWnd, WM_SIZE, OnSize);
  23. HANDLE_MSG(hWnd, WM_PAINT, OnPaint);
  24. HANDLE_MSG(hWnd, WM_DESTROY, OnWinDestroy);
  25. }
  26. return DefWindowProc( hWnd, message, wParam, lParam );
  27. }

与使用HANDLE_MSG宏之前的代码相比,我们根本不需使用LOWORD、HIWORD来提取cxCleint及cyClient的信息,OnSize函数的参数已经有cx及cy,而且还传进一个表示窗口变化类型的参数state,如SIZE_RESTORED, SIZE_MAXSHOW等。ps与hdc这两个变量移至OnPaint函数中而成为真正的局域变量。在switch分支语句中,对于每一个消息,都使用HANDLE_MSG宏清晰地将消息与消息处理函数对应起来,代码非常简洁。而无论是在消息处理函数,或是switch分支中,我们均无需显式地加上break语句。

下面我们来看看HANDLE_MSG宏是如何做到这一点的。HANDLE_MSG宏的定义如下所示:

  1. #define HANDLE_MSG(hwnd, message, fn) /
  2. case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

HANDLE_MSG(hwnd, message, fn)是宏的签名。hwnd是需处理消息的窗口句柄,message是消息,fn是指向负责消息处理的函数指针。当编译器遇到此宏,将在编译时将其转换为

  1. case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

的形式。##是ANSI C标准中的预处理器,用于将前后两个符号直接连接起来。因此,当message为WM_SIZE时,HANDLE_##message就变成:

  1. HANDLE_WM_SIZE

因此,对于

  1. HANDLE_MSG(hWnd, WM_SIZE, OnSize)

编译器将转换为:

  1. case WM_SIZE:
  2. return HANDLE_WM_SIZE(hwnd, wParam, lParam, OnSize)

我们注意到,尽管HANDLE_MSG宏中未使用wParam及lParam参数,但展开宏后,这两个参数均加进来了。

HANDLE_WM_SIZE也是一个在WindowsX.h中定义的宏,其原型如下:

  1. #define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) /
  2. ((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)

正是在HANDLE_WM_SIZE宏中,自动将wParam, lParam的高位及低位分别抽出,作为OnSize函数的实参进行传递。

应注意,不同消息处理函数的参数列表是不一样的。如OnSize函数,其参数列表包括HWND, UINT, int, int, 而OnPaint、OnWindDestory函数均只有一个HWND参数。那么,如何声明这些消息处理函数的签名?很简单,在WindowsX.h文件中找到定义HANDLE_WM_SIZE的地方,其上面有一行注释:

  1. /* void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy) */
  2. #define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) /
  3. ((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)

Cls_OnSize函数已经给出了函数的签名,因此,我们只需将此签名复制过来,并将Cls_OnSize更名为自己选择的函数名称即可。

http://blog.csdn.net/daiyutage/article/details/17241161

http://blog.csdn.net/cocoasprite/article/details/43208717

使用HANDLE_MSG宏简化Win32应用的开发的更多相关文章

  1. 5款帮助简化的HTML5 Audio开发的Javascript类库

    HTML5的audio标签提供了我们方便控制声音的功能,可是使用原生的HTML5来开发声音或者音乐相关的项目仍旧很的麻烦.在今天这篇文章中,我们将介绍5款帮助你简化开发的javascript audi ...

  2. 架设WIN32汇编程序的开发环境

    笔者在学习Windows下的图形界面应用程序(GUI,Graphical User Interface)的时候碰到的第一个麻烦就是架设WIN32汇编程序的开发环境,在这里笔者愿意和大家分享这段经历. ...

  3. 第1章—Spring之旅—简化Spring的java开发

    简化Spring的java开发 1.1简介 区别于EJB的特性 简化javaBean,为了降低java开发的复杂性,Spring采取了以下4种关键策略: 基于POJO的轻量级和最小入侵性编程 通过依赖 ...

  4. (转)可简化iOS 应用程序开发的6个Xcode小技巧

    Xcode是iPhone和iPad开发者用来编码或者开发iOS app的IDE.Xcode有很多小巧但很有用的功能,很多时候我们可能没有注意到它们,也或者我们没有在合适的水平使用这些功能简化我们的iO ...

  5. 关于C++的宏:WIN32和DEBUG

    判断平台相关,判断程序是属于debug版本还是release版本,我们会这么做. #ifdef WIN32 #else #endif #ifdef DEBUG // 如果是调试版本 #else //发 ...

  6. 最简化的DirectX 11开发环境的配置 VS2010

    转载自:http://blog.csdn.net/zhmxy555/article/details/7672101 在编写基于DirectX 11的应用程序之前,我们当然需要在IDE中加入Direct ...

  7. JeeSite 4.0 简化业务逻辑层开发

    2019独角兽企业重金招聘Python工程师标准>>> 引言 对于业务逻辑层的开发重复代码很多,尽管有代码生成器,但从代码量总的来说还是比较多,所以就有了以下抽象类及工具,对一些常用 ...

  8. Jaxb的优点与用法(bean转xml的插件,简化webservice接口的开发工作量)

    一.jaxb是什么 JAXB是Java Architecture for XML Binding的缩写.可以将一个Java对象转变成为XML格式,反之亦然.     我们把对象与关系数据库之间的映射称 ...

  9. 用block做事件回调来简化代码,提高开发效率

       我们在自定义view的时候,通常要考虑view的封装复用,所以如何把view的事件回调给Controller就是个需要好好考虑的问题, 一般来说,可选的方式主要有target-action和de ...

随机推荐

  1. Coverage报告生成

    Coverage报告生成 覆盖率 覆盖率驱动的验证方法中覆盖率报告的生成至关重要,现在介绍一下使用DVE和URG生成覆盖率报告的步骤. 使用VCS生成数据 在VCS的运行脚本中添加-cm cond+f ...

  2. 附加数据库 对于server XXX失败

            近期在学习MVC+EF,看着视频做小demo.EF这一块须要涉及到数据库的连接,视频中所讲的样例与先前牛腩新闻系统数据库挺类似的. 所以,就偷个懒,利用这个数据库,可是在附加的时候出错 ...

  3. Linux上安装JDK 分类: B1_JAVA B3_LINUX 2014-08-29 15:12 449人阅读 评论(0) 收藏

    1.下载rpm文件并安装 rpm -ivh jdk-7u51-linux-x64.rpm 2.修改/etc/profile文件,增加以下配置 export JAVA_HOME=/usr/java/jd ...

  4. 微信小程序初步运营方案

    小程序的运营方案有很多种,目前我们遇到两个事情需要解决:1.问答的内容,这块也是大家比较关心的话题.内容的定位和细节. 2.预热与推广,就这两个问题,我列出了一些自己的想法和小程序初步运营方案,有不足 ...

  5. [React] Update Component State in React With Ramda Lenses

    In this lesson, we'll refactor a React component to use Ramda lenses to update our component state. ...

  6. [Angular Router] Lazy loading Module with Auxiliary router

    Found the way to handle Auxiliary router for lazy loading moudle and erge load module are different. ...

  7. 每天一个JavaScript实例-处理textarea中的字符成每一行

    <!doctype html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  8. 以Network Dataset(网络数据集)方式实现的最短路径分析

    转自原文 以Network Dataset(网络数据集)方式实现的最短路径分析 构建网络有两种方式,分别是网络数据集NetworkDataset和几何网络Geometric Network,这个网络结 ...

  9. SQL Server高速生成SQL增删改查语句

    你还在手写程序生成SQL语句吗?你还在为由于马虎出错的SQL语句而感到无语吗?你还在为不知如何表达复杂的SQL语句而纠结吗?假设你的回答为"是".那你就OUT啦.快来试试应用SQL ...

  10. MongoDB Shell 经常使用操作

    数组查询 数组查询 MongoDB 中有子文档的概念.一个文档中能方便的嵌入子文档,这与关系性数据库有着明显的不同,在查询时,语法有一些注意点. 样例代码,假如我们的一个集合(tests)中存在标签键 ...