WPARAM
WPARAM,消息响应机制
wParam和lParam 这两个是Win16系统遗留下来的产物,在Win16API中WndProc有两个参数:一个是WORD类型的16位
整型变量
;另一个是LONG类型的32位整型变量。因此根据
匈牙利命名法
,16位的变量就被命名为wParam, 32位的变量就被命名为lParam。
到了Win32API中,原来的16位变量也被扩展为32位,因此此时wParam和lParam的大小完全相同。在Win32API的早期,为了保证和Win16API的代码可移植性MS定义了WPARAM和LPARAM两个宏。当时保留了w前缀的原因一方面是由于WPARAM宏也以W开头,还有也因为要提醒程序员注意到可移植性,当然到了现在Win16早已退出历史舞台,这个前缀也就约定俗成的沿用下来了。
例如:示例程序.cpp
int OnTrayNotify(WPARAM wID,LPARAM lEvent)
if(wID == TRAYNOTIFYDATA.uID)
return 0;
if(lEvent == WM_LBUTTONDOWN)
{ 处理代码 }
else if(lEvent == WM_RBUTTONDOWN)
{ 处理代码 }
return 0;
}
WPARAM 和 LPARAM 本质上没有什么区别:
都是32位数,
但是区别也还是有的:除了关于16位的的
历史问题外,MICROSOFT在使用时两种参
数分别代表不同的含义和内容,WPARAM常常代表一些控件的ID或者高位底位组合起来分别表示鼠标的位置,如果消息的发送者需要将某种结构的
指针
或者是某种类型的句柄时,习惯上用LPARAM来传递,可以参考各种控件的通知消息:可以查看:EN_CHANGE (EDIT控件的一个通知消息),CBEM_INSERTITEM(可扩展
组合框
的可接受消息)等等来加以领会。
理论上在使用自定义消息时,WPARAM LPARAM的含义可以程序员任意指定的,但是最好遵从MFC中的习惯。在调用SendMessage()函数时,第二个参数是WPARAM,第三个参数是这个消息的LPARAM,但是你在程序中某个类中写下ON_MESSAGE()宏来处理这个消息时,处理函数SomeHandler(WPARAM,LPRAM(默认是0))中解释这两个参数时必须按照SendMessage调用中的意义来进行。
消息响应机制
1、消息的组成:
一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。例如当
菜单
选中之后会有
WM_COMMAND
消息发送,WPARAM的低字中(LOWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。
2、谁将收到消息:
一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。例如你希望对
菜单
选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行
图形输出
就必须对WM_PAINT进行处理。
3、未处理的消息到那里去了:
M$为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。正因为有了这个默认窗口过程我们才可以利用Windows的窗口进行开发而不必过多关注窗口各种消息的处理。例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。
4、
窗口句柄
:
说到消息就不能不说窗口句柄,系统通过窗口句柄来在整个系统中唯一标识一个窗口,发送一个消息时必须指定一个窗口句柄表明该消息由那个窗口接收。而每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口一的句柄被发送到窗口一而不是窗口二。
5、示例:
下面有一段
伪代码
演示如何在窗口过程中处理消息
LONG yourWndProc(HWND hWnd,UINT uMessageType,WPARAM wP,LPARAM)
switch(uMessageType)
{//使用SWITCH语句将各种消息分开
case(WM_PAINT):
doYourWindow(...);//在窗口需要重新绘制时进行输出
break;
case(WM_LBUTTONDOWN):
doYourWork(...);//在鼠标左键被按下时进行处理
break;
default:
callDefaultWndProc(...);//对于其它情况就让系统自己处理
break;
}
接下来谈谈什么是
消息机制
:
系统将会维护一个或多个
消息队列
,所有产生的消息都会被放入或是插入队列中。系统会在
队列
中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该
窗口的程序的
消息循环
。每一个运行的程序都有自己的
消息循环
,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时
消息循环
就将控制权交给系统所以Windows可以同时进行多个任务。下面的
伪代码
演示了
消息循环
的用法:
while(1){
id=getMessage(...);
if(id == quit)
break;
translateMessage(...);
}
当该程序没有消息通知时getMessage就不会返回,也就不会占用系统的CPU时间。
转载地址:http://blog.sina.com.cn/s/blog_8795b0970101c68c.html
按照孙鑫的教程添加自定义消息时,如果是VC6.0开发环境,也许没有什么 问题,但在VS2008中编译会报错的 无法从"void (__thiscall CtestDlg::* )(void)"转换为"LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)" 这是因为VS2008中消息返回值不允许为void,且消息参数不能为空,消息映射三处分别如下 #define
转自原文 error C2440 “static_cast” 无法从“void (__thiscall C* )(void)... error C2440: “static_cast”: 无法从“LRESULT (__thiscall CTextProgressCtrl::* )(UINT,LPCT