标题:使用HANDLE_MSG宏简化Win32应用的开发
只看楼主
szchina
Rank: 1
等 级:新手上路
帖 子:99
专家分:0
注 册:2012-7-31
 问题点数:0 回复次数:5 
使用HANDLE_MSG宏简化Win32应用的开发
Win32应用中的回调函数WndProc用于接收Windows向应用程序直接发送的消息,以及响应消息。大多情况下,我们这样编写代码:

[cpp] view plaincopy
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宏后的代码:

[cpp] view plaincopy
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宏的定义如下所示:

[cpp] view plaincopy
#define HANDLE_MSG(hwnd, message, fn) /  
    case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))  

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

[cpp] view plaincopy
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))  

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

[cpp] view plaincopy
HANDLE_WM_SIZE  

因此,对于

[cpp] view plaincopy
HANDLE_MSG(hWnd, WM_SIZE, OnSize)  

编译器将转换为:

[cpp] view plaincopy
case WM_SIZE:  
    return HANDLE_WM_SIZE(hwnd, wParam, lParam, OnSize)  

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

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

[cpp] view plaincopy
#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的地方,其上面有一行注释:

[cpp] view plaincopy
/* 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更名为自己选择的函数名称即可。
搜索更多相关主题的帖子: message Windows 应用程序 开发 
2012-09-12 08:28
longlong89
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:广州
等 级:小飞侠
威 望:6
帖 子:1043
专家分:2754
注 册:2009-8-18
得分:0 
谢谢分享

想象力征服世界
2012-09-13 20:40
姻脂梦
Rank: 6Rank: 6
等 级:侠之大者
帖 子:264
专家分:424
注 册:2012-7-3
得分:0 
膜拜楼主
2012-09-13 21:17
信箱有效
Rank: 13Rank: 13Rank: 13Rank: 13
等 级:蒙面侠
威 望:9
帖 子:1102
专家分:4268
注 册:2012-6-19
得分:0 
转贴  又不给分,不性福。
2012-09-13 21:42
zhangqi_gsts
Rank: 6Rank: 6
来 自:甘肃天水
等 级:侠之大者
威 望:1
帖 子:227
专家分:457
注 册:2011-3-27
得分:0 
貌似昨晚我刚在百度里找到过
2012-09-15 23:29
liuxia
Rank: 1
等 级:新手上路
帖 子:6
专家分:4
注 册:2013-2-24
得分:0 
初学者的好东东。多谢楼主的分享。
2013-04-21 09:25



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-381220-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.581775 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved