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. php实现找两个链表的第一个公共结点(实例演示)

    php实现找两个链表的第一个公共结点(实例演示) 一.总结 因为是链表,第一个节点公共之后,后面所有的节点都公共了 画个图实例演示一下,会超清晰且简单 二.php实现找两个链表的第一个公共结点 题目描 ...

  2. 使用DOT语言和Graphviz绘图(翻译)

    Casa Taloyum About Me Blog Archives 使用DOT语言和Graphviz绘图(翻译) Date Wed 26 November 2014 Tags graphviz / ...

  3. 【u015】兽径管理

    [问题描述] 约翰农场的牛群希望能够在 N 个(1<=N<=200)草地之间任意移动.草地的编号由 1到N.草地之间有树林隔开.牛群希望能够选择草地间的路径,使牛群能够从任一 片草地移动到 ...

  4. 海思hi3716c机顶盒接usb摄像头和usb无线耳机时,无线耳机有时没有声音

    两个USB设备各自是: A:USB摄像头带录音功能,但不带放音功能. B:USB无线耳机是使用USB转2.4G的无线耳机. 详细现象: 1, A,B两者同一时候插上机顶盒,并开机进入android,此 ...

  5. [Ramda] Refactor to Point Free Functions with Ramda using compose and converge

    In this lesson we'll take some existing code and refactor it using some functions from the Ramda lib ...

  6. 【hdu 3032】Nim or not Nim?

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s) ...

  7. FMDB数据库框架

    nFMDB   nFMDB n什么是FMDB pFMDB是iOS平台的SQLite数据库框架 pFMDB以OC的方式封装了SQLite的C语言API p nFMDB的优点 p使用起来更加面向对象,省去 ...

  8. javaScript判断输入框是否为空

    其中获得和失去焦点的时候都判断了一次 <script> function fun01(f,s){//有参函数 参数不需要参数类型!! try{ var v = document.getEl ...

  9. NOIP模拟 拆网线 - 贪心策略+dp

    题目大意: 给一颗n个节点的树,保留最少的边,使得每个连通块的大小都大于等于2,并且连通块的点数和等于k. 题目分析: 要想留下的边数最少,就要尽量多的选择单独的边,这里就要贪心:尽可能多的选择单独的 ...

  10. python request 代理/超时/证书

    import requests headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) A ...