理论上在使用自定义消息时,WPARAM、LPARAM的含义可以程序员任意指定的,但是最好遵从MFC中的习惯。在调用SendMessage()函数时,第二个参数是WPARAM,第三个参数是这个消息的LPARAM,但是你在程序中某个类中写下ON_MESSAGE()宏来处理这个消息时,处理函数SomeHandler(WPARAM,LPRAM(默认是0))中解释这两个参数时必须按照SendMessage调用中的意义来进行。
SendMessage的基本结构如下:
SendMessage(
HWND hWnd, //消息传递的目标窗口或线程的句柄。
UINT Msg, //消息类别(这里可以是一些系统消息,也可以是自己定义,下文具体介绍,)
WPARAM wParam, //参数1 (WPARAM 其实是与UINT是同种类型的,
//在vc编译器中右键有个“转到WPARAM的定义”的选项可以查看。
LPARAM lParam); //参数2
例如:::SendMessage(this->m_hWnd,WM_MY_DOSOME, (WPARAM) 0, (LPARAM) 0);
SendMessage及WPRAME、LPARAME
typedef unsigned int UINT
typedef UINT WPARAM
typedef LONG LPARAM
typedef LONG LRESULT
MFC中的SendMessage()则是,谁调用它,则其就是接收消息的载体,必须实现消息。例如:pView->SendMessage(),则有pView窗口接收消息(视也是一个窗口)。
消息响应机制
1、消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)组成。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。例如当菜单选中之后会有WM_COMMAND消息发送,WPARAM的低字中(LOWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。
2、谁将收到消息:一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。例如你希望对菜单选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行图形输出就必须对WM_PAINT进行处理。
3、未处理的消息到那里去了:MS为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。正因为有了这个默认窗口过程我们才可以利用Windows的窗口进行开发而不必过多关注窗口各种消息的处理。例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。
4、窗口句柄:说到消息就不能不说窗口句柄,系统通过窗口句柄来在整个系统中唯一标识一个窗口,发送一个消息时必须指定一个窗口句柄表明该消息由那个窗口接收。而每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口一的句柄被发送到窗口一而不是窗口二。
消息机制:
系统将会维护一个或多个消息队列,所有产生的消息都回被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统所以Windows可以同时进行多个任务。
MFC中SendMessage的用法与相应函数的添:
1、::SendMessage(AfxGetMainWnd()->m_hWnd,WM_CHILDFRAMEDBCLK ,0,0);
其中WM_CHILDFRAMEDBCLK是自定义的消息ID(其ID为WM_USER+1),AfxGetMainWnd()->m_hWnd是获得主窗口(这里不能使用GetParent()->m_hWnd或者GetParentFrame()->m_hWnd,因为这是获得父窗口,但父窗口不一定是主窗口,一定要注意,不然消息就会发错导致接收不到。
2、然后接下来定义一个消息需要映射的函数,如下:
afx_msg LRESULT OnChlidFrameDBClick(WPARAM wParam, LPARAMlParam);
注意格式必须是:两个参数必不可少,返回类型一定为LRESULT,网上很多文章都忽略了这两点,这也是网上文章普遍错误的地方。
3、添加消息函数映射
ON_MESSAGE(WM_CHILDFRAMEDBCLK,OnChlidFrameDBClick)
注意这里必须是ON_MESSAGE, 不能使用ON_COMMAND, 前者主要针对用户自定义消息,后者针对WM_COMMAND命令,比如菜单、工具栏等.
4、实现消息函数:
我们在接收窗体里定义一个这样的事情(过程),
LRESULTCMainFrame::OnChlidFrameDBClick(WPARAM wParam, LPARAM lParam)
{
CancelFullScreenWin(); // 这里调用了一个使子窗口全屏的自写函数,我就不贴出来了,以后专题将的时候会提到
return 0;
}
把要传递的变量的指针作为参数传递就行了。
DWORD或其小于等于DWORD(一般为4字节)长度的变量直接传再强转:
unsigned int a =12345;
unsigned int* b = &a;
SendMessage(DWORD(a), DWORD(b));
OnMessage(DWORD wParam, DWORD lParam)
{
unsigned int a =(unsigned int)wParam;
unsigned int* b = (unsigned int*)lParam;
...
}
复杂数据传指针再强转(或提升):
struct a_t
{
int aa;
char ab;
};
a_t a;
SendMessage(DWORD(&a), DWORD(0));
OnMessage(DWORD wParam, DWORD lParam)
{
a_t* pa =(a_t*)wParam;
cout << pa->aa << endl;
...
}