使用HANDLE_MSG宏简化Win32应用的开发
http://blog.csdn.net/daiyutage/article/details/17241161
Win32应用中的回调函数WndProc用于接收Windows向应用程序直接发送的消息,以及响应消息。大多情况下,我们这样编写代码:
- LRESULT CALLBACK WndProc(HWND hWnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam )
- {
- int cxClient, cyClient;
- PAINTSTRUCT ps;
- HDC hdc;
- switch( message )
- {
- case WM_SIZE:
- cxClient = LOWORD(lParam);
- cyClient = HIWORD(lParam);
- break;
- case WM_PAINT:
- hdc = BeginPaint( hWnd, &ps );
- EndPaint( hWnd, &ps );
- break;<br />
- case WM_DESTROY:
- PostQuitMessage( 0 );
- break;
- }
- return DefWindowProc( hWnd, message, wParam, lParam );
- }
这种方式通过switch分支语句分理处理各个消息,结构简单明了。但有2个问题:
- 在所处理的消息多了后,全部代码都集中于一个switch语句中,变量容易相互污染,且代码很长,不容易定位代码。
- 大多数的消息都有相应的WPARAM、LPARAM参数,但对于每个消息,其WPARAM、LPARAM参数的具体内容又不一致。就像上面WM_SIZE中的代码,我们怎么知道cyClient、cyClient的信息就放在lParam而不是wParam中,且cxClient的信息在lParam的低位,cyClient的信息在lParam的高位?我们需要随时查询SDK文档以了解这两个参数中各有什么含义,以及如何恰当地将这些参数抽取出来。不管怎样,上面的代码实际上就是个让人一团雾水的魔术代码(Magic Code).
WindowsX.h定义了许多宏,可以帮助我们解决上述这些问题。其中HANDLE_MSG宏可以大大简化Win32开发。下面我们先看使用HANDLE_MSG宏后的代码:
- void OnSize(HWND hwnd, UINT state, int cx, int cy)
- {
- }
- void OnPaint(HWND hWnd)
- {
- PAINTSTRUCT ps;
- HDC hdc;
- hdc = BeginPaint( hWnd, &ps );
- EndPaint( hWnd, &ps );
- }
- void OnWinDestroy(HWND hWnd)
- {
- PostQuitMessage(0);
- }
- LRESULT CALLBACK WndProc(HWND hWnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam )
- {
- switch( message )
- {
- HANDLE_MSG(hWnd, WM_SIZE, OnSize);
- HANDLE_MSG(hWnd, WM_PAINT, OnPaint);
- HANDLE_MSG(hWnd, WM_DESTROY, OnWinDestroy);
- }
- return DefWindowProc( hWnd, message, wParam, lParam );
- }
与使用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宏的定义如下所示:
- #define HANDLE_MSG(hwnd, message, fn) /
- case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
HANDLE_MSG(hwnd, message, fn)是宏的签名。hwnd是需处理消息的窗口句柄,message是消息,fn是指向负责消息处理的函数指针。当编译器遇到此宏,将在编译时将其转换为
- case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
的形式。##是ANSI C标准中的预处理器,用于将前后两个符号直接连接起来。因此,当message为WM_SIZE时,HANDLE_##message就变成:
- HANDLE_WM_SIZE
因此,对于
- HANDLE_MSG(hWnd, WM_SIZE, OnSize)
编译器将转换为:
- case WM_SIZE:
- return HANDLE_WM_SIZE(hwnd, wParam, lParam, OnSize)
我们注意到,尽管HANDLE_MSG宏中未使用wParam及lParam参数,但展开宏后,这两个参数均加进来了。
HANDLE_WM_SIZE也是一个在WindowsX.h中定义的宏,其原型如下:
- #define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) /
- ((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的地方,其上面有一行注释:
- /* void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy) */
- #define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) /
- ((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
最新文章
- CTO和技术副总裁应该如何分工?谁才是技术领导者?
- SESSION机制
- [CareerCup] 17.14 Unconcatenate Words 断词
- C# List 中 Find 方法
- Array类型(一)
- NET5实践:项目创建-结构概述-程序运行-发布部署
- iOS获取各种数据方法整理以及IDFA与IDFV使用环境
- 如何回滚请求<;复制系统初始的数据>;所处理的数据
- jmeter数据库,charles抓包,Python循环语句
- 【JVM】JVM垃圾收集器、垃圾收集算法、无用对象
- tensorflow训练中出现问题Couldn&#39;t open CUDA library cupti64_80.dll
- python optparser模块
- maven项目依赖jar包报 java.lang.classnotfoundexception:Type com.xx.xx.xxx not present 的解决
- 全栈性能测试修炼宝典--Jmeter实战(三)
- 【win7 + win server 2008】设置定时任务,设置.bat 文件去执行php脚本 == 用来配合爬虫程序简直不要太爽
- 使用 WinDbg 分析dump文件
- IIS 6 备忘
- md5sum/opensll md5
- 20145211《网络对抗》逆向及BOF基础实践
- pthread中取消线程
热门文章
- 安装Centos时“sda必须有一个GPT磁盘标签”
- 9个完整android开源app项目
- 二、Reids基础命令--字符串
- IT增值服务-客户案例(三):合肥薪火科技,Java和P2P网络借贷系统开发指导
- Expression Blend 的点滴(1)--ListBox华丽大变身
- 【BZOJ 1021】[SHOI2008]Debt 循环的债务
- 【 D3.js 高级系列 — 2.0 】 机械图 + 人物关系图
- vue webpack添加jQuery
- WinForm - 窗体淡入效果界面的简单实现方法
- Numpy Usage Introduction