关于windowsx.h的介绍

来源:互联网 发布:最大公约数 c语言 编辑:程序博客网 时间:2024/06/11 07:37
很多初中级程序员用C/C++编写WindwosAPI的程序时,经常面对面条式的switch...case语句块
当你在Window过程(回调函数、下称过程)中加入大量诸如WM_COMMAND orWM_CHAR的消息捕获时。真是一场噩梦。
关于上千行代码的Window过程的问题,随着 C/C++ 7.0 编译器和Windows SDK for Windows3.1发行时带的一个头文件而被解决。
这个头文件是 <windowsx.h>以及所包含的大量的有用的宏。按照微软的说法:这些头文件所带来的便利可重复用于下面这些地方(Groups)


.在C程序中使用STRICT宏进行严格的类型检查。
.在windows程序中用宏简化公共性操作。
.使用控件宏同windows控件进行通讯。
.windows环境下的消息解析器(messagecrackers)(是一个方便的、可移植的、类型安全的处理消息的方法)以及和他相关的参数和返回值


因为消息解析器向导是用于消息解析器的,其他由这头文件带来的一些有用的宏,我就跳过不讲了,如果你想看看关于
WINDOWSX.H的简要介绍,可以看 MS Knowledge Base Article #83456.
(http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q83/4/56.asp)
好,让我们说下消息解析器的优点,当然也包括为什么这里提供的这个工具是如此有用。
当你使用W32SDK编程,用windows过程(通常叫做WndProc)处理窗口和对话框消息时,使用swich-case来捕获你需要处理的消息是
非常普遍的做法。假设你想处理WM_COMMAND, WM_KEYUP, WM_CLOSE andWM_DESTROY消息,你是这样作的:

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_COMMAND:
// ...
break;

case WM_KEYUP:
// ...
break;

case WM_CLOSE:
// ...
break;

case WM_DESTROY:
//...
break;

default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
这是自从Windows1.0诞生以来处理消息最常见的风格了。而且很肯定,它工作得很好。
但问题是,当你加入一个或多个复杂的特色到你的程序中时,如MDI,OLE 公共控件等等,
结果形成了一个上千行的Window过程,你开始用PageDn和PageUp来查找你想要修改的消息处理代码了。

消息解析器的第一个好处就是:他把面条式的case标签转换成类似MFC中易于维护和处理的函数。
第二个好处是:处理函数中合适的参数。你可以简单使用switch(id)代替原先的switch(LOWORD(wparam)),
因为消息解析器传递给你的是 "已解析 "的参数,他等价于LOWORD(wparam)。

HANDLE_MSG 这个消息处理宏在windowx.h中的定义如下:
#define HANDLE_MSG(hwnd, message, fn) \
case (message) : return HANDLE_##message((hwnd), (wParam),(lParam), (fn))
你想要把你的代码做成 "消息解析 "版的,你需要提供一个解析宏HANDLE_MSG及其函数来处理你的消息.
在window过程里HANDLE_MSG宏需要三个参数:窗口句柄(hwnd),消息(WM_XXXX),处理你消息的函数(function)。
为更好地解释这个:看下面,我们把上面那段代码转换成了下面的代码:

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG (hwnd, WM_COMMAND, OnCommand);
HANDLE_MSG (hwnd, WM_KEYUP, OnKeyup);
HANDLE_MSG (hwnd, WM_CLOSE, OnClose);
HANDLE_MSG (hwnd, WM_DESTROY, OnDestroy);
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}

哇,太好了,紧凑且易于管理的window过程。现在你可以去定义你的消息处理函数了(OnKeyUp, OnClose, andOnDestroy)
还有一个真正的好处,你可以在visual studio IDE 环境中直接跳转到消息处理函数。

图片:...(看原文)

有个问题是:当你每加入一个消息处理,你必须在windowx.h中查找相关参数的定义。
因为消息处理参数的格式是明确的而不能由你随心所欲。但在头文件中进行重复搜索是乏味且易出错的。

消息解析向导工具用于解决这个:他允许你粘贴你需要的函数参数,
而你如果只是打草稿,他也会在在你消息处理中写上一个模板化的window或对话框过程 (??这句有疑问)
消息前驱宏(message fowarding): WINDOWSX.H 的另一个特色 (消息前向?)
WINDOWSX.H另一个特色是消息前驱的可能性,
它是用于 "解压 "消息处理参数到其他函数调用(如PostMessage, SendMessage,CallWindowProc等)所需要的合适的WPARAM和LPARAM值。
假设我们想用SendMessage发送一个WM_COMMAND消息到父窗口, "模拟"一个在名为IDC_USERCTL控件上的双击(通过发送BN_DBLCLK的通知码)
我们通常这么做的:

SendMessage (hwndParent, WM_COMMAND,
MAKEWPARAM(IDC_USERCTL, BN_DBLCLK),
(LPARAM)GetDlgItem(hwnd, ID_USERCTL));
这是相当复杂的语法。SendMessage希望WPARAM参数的低字是控件ID而高字是通知码,LPARAM参数是控件句柄,句柄我们通过GetDlgItem这

个API函数得到。
上述代码可以被转换为WINDOWSX.H的消息前驱宏,FORWARD_WM_xxxxx。
对于每个消息,消息前向宏用同样的方式 "打包 "消息解析向导创建的函数参数,
并且传递给你的处理函数 "已解压 "的参数(LPARAM/WPARAMs)。
例如:对于一个myWnd窗口的WM_COMMAND消息,消息解析器向导将生成如下的函数原形:

void myWnd_OnCommand (HWND hwnd, int id, HWND hwndCtl, UINTcodeNotify)

那么,这些解析的参数也同样用于消息前驱宏,这样上面那使人混乱的SendMessage调用可以简化为:

FORWARD_WM_COMMAND (hwndParent, IDC_USERCTL,
GetDlgItem(hwnd, ID_USERCTL), BN_DBLCLK, SendMessage