具体是这么说:“在Win 3.x中,WPARAM是16位的,而LPARAM是32位的,两者有明显的区别。因为地址通常是32位的,所以LPARAM 被用来传递地址,这个习惯在Win32 API中仍然能够看到。在Win32 API中,WPARAM和LPARAM都是32位,所以没有什么本质的区 别。
Windows的消息必须参考帮助文件才能知道具体的含义。如果是你定义的消息,愿意怎么使这两个参数都行。但是习惯上,我们愿意使用LPARAM传 递地址,而WPARAM传递其他参数。”
在Win32API的早期,为了保证和Win16API的代码可移植性MS定义了WPARAM和LPARAM两个宏。
当时保留了w前缀的原因一方面是由于WPARAM宏也已W开头,还有也因为要提醒程序员注意到可移植性,当然到了现在Win16早已退出历史舞台,这个前缀也就约定俗成的沿用下来了。
例如:主程序MyDlg.cpp
1.自定义消息:#define WM_TRAY WM_USER 100
2.函数原形:afx_msg LRESULT OnTrayNotify(WPARAM wParam,LPARAM lParam);
3.消息映射:ON_MESSAGE(WM_TRAY,OnTrayNotify)
4.原函数:
LRESULT CMyDlg::OnTrayNotify(WPARAM wParam,LPARAM lParam)
{
return m_tray.OnTrayNotify(wParam,lParam);
}
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的高字中(HIWORD(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时间。
在Win32 SDK中消息本身是作为一个结构体记录传递给应用程序的,这个记录中包含了消息的类型以及其他信息。这个记录类型叫做MSG,它在window中是这样声明的:
typedef struct tagMSG { // msg
HWND hwnd; //窗口句柄
UINT message; //消息常量标识符
WPARAM wParam; //32位消息的特定附加信息,具体表示什么处决于message
LPARAM lParam; //32位消息的特定附加信息,具体表示什么处决于message
DWORD time; //消息创建时的时间
POINT pt; //消息创建时的鼠标位置
} MSG;
hwnd 接收消息的32位窗口句柄。窗口可以是任何类型的屏幕对象,因为Win32能够维护大多数可视对象的句柄(窗口、对话框、按钮、编辑框等)。
message 用于区别其他消息的常量值,这些常量可以是Windows单元中预定义的常量,也可以是自定义的常量。
wParam 通常是一个与消息有关的常量值,也可能是窗口或控件的句柄。 lParam 通常是一个指向内存中数据的指针。由于wParam,lParam和指针都是32位的,需要时可以强制类型转换。具体表示什么,与message相关,他们是事先定义好的。
如果自定义消息:#define WM_MYMESSAGE WM_USER+100,需确定wParam,lParam的意义 (假设wParam=0时发送数据,wParam=1时接收数据,lParam为CMyClass* 指针,指向一个CMyClass对象,准备要发送的数据或接收数据 发送WM_MYMESSAGE时 SendMessage(hwnd,WM_MYMESSAGE,0,pMyClassObject) 接收消息的窗口,接收WM_MYMESSAGE中(CMyClass*)lParam参数即pMyClassObject传过来的数据
MFC数据类型WPARAM 窗口函数或callback函数的一个参数
实际上所有的消息响应都有WPARAM和LPARAM的存在,只是有些消息响应WPARAM和LPARAM没有意义,所以在MFC封装后有些固定的消息响应函数看不到WPARAM和LPARAM,但依然可以通过GetCurrentMessage()取得当前的消息来查看WPARAM和LPARAM。
WPARAM //typedef UINT WPARAM;control identifier
LPARAM //typedef LONG LPARAM;notification messages
Windows中的消息由,消息号,字参数(lParam),长字参数(wParam)组成。是包含有关消息的附加信息,随不同的消息有所不同。例如在鼠标消息中参数lParam 包含鼠标光标坐标,wParam包含一个指示各种虚键状态的值(如按下鼠标左键还是右键。。。).
从消息参数中获取字符串和位置信息存放到子串口类的成员函数中。字符串m_string为什么对应wParam,点m_point对应lParam
LRESULT CChildView::OnReceive(WPARAM wParam,LPARAM lParam)
{
m_string = *((CSring *)wParam);
m_point = *((CPoint *)lParam);
Invalidate();
return 0;
程序代码*在对话框中取出数据,并向其他窗口发送消息和数据,将数据指针作为一个参数发送*/
void CTestDlg2::OnCommBtn()
{
char szOut[30];
GetDlgItemText(IDC_OUT,szOut,30);
m_pParent->SendMessage(WM_DLG_NOTIFY,(WPARAM)szOut);
}
/*在消息接收窗口中*/
/*映射消息处理函数*/
ON_MESSAGE(WM_DLG_NOTIFY,OnDlgNotifyMsg)
/*在视图中绘制出字符串 m_szOut*/
void CMy53_s1View::OnDraw(CDC* pDC)
{
CMy53_s1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->TextOut(0,0,"Display String");
pDC->TextOut(0,20,m_szOut);
}
/*处理通知消息,保存信息并更新显示*/
LONG CMy53_s1View::OnDlgNotifyMsg(WPARAM wP,LPARAM lP)
{
m_szOut=(char*)wP;
Invalidate();
return 0;
}
一个字符串的地址通过WPARAM来标识,再通过Windows消息发送出去;之后在消息处理函数中WPARAM接受到的参数就是该地址,然后就可以对该地址进行操作了~~~
这是Windows消息机制中经常用到的两个data type,呵呵