windows是消息驱动的,系统定义了很多消息,但同时它也允许我们自己定义消息。自定义消息有两种方法:
(1)在WM_USER上加一个值来定义消息
WM_USER(0x400)到0x7FFF都可以用来自定义消息(一般取WM_USER+100)。以MFC对话框程序为例,定义自己的消息要分以下几个步骤
首先在发送端:
①定义消息。在xxxDlg.cpp(xxx为发送端工程名)头部定义自己的消息WM_MY_OWN_MSG(名字随意)
#define WM_MY_OWN_MSG WM_USER + 100
②然后就可以添加控件的响应函数来发送刚刚定义的消息了
void CSendMessageDlg::OnSendUsermsg()
{
// TODO: Add your control notification handler code here
CString szUserMsg;
szUserMsg.Empty();
CWnd::GetDlgItemText(IDC_EDIT_USERMSG,szUserMsg);
//输入不能为空
if(szUserMsg.GetLength() == 0)
{
CWnd::MessageBox("Please input sth");
return;
}
UINT uMsg;
uMsg = atoi(szUserMsg);
CWnd *pWnd = CWnd::FindWindow(NULL,TEXT("RecieveMsg 进程间通信接收端"));
if(pWnd == NULL)
{
AfxMessageBox("Unable to find DataRecieve");
return;
}
//将消息发到接收端,编辑框中的内容存在LPARAM里了
pWnd->SendMessage(WM_MY_OWN_MSG,NULL,(LPARAM)uMsg);
}
pWnd->SendMessage(WM_MY_OWN_MSG,NULL,(LPARAM)uMsg);
一个windows消息要传递的信息都存在WPARAM 和LPARAM这两个参数里,由于这里WM_MY_OWN_MSG这个消息是我自己定义的,所以具体哪个参数存放编辑框中的内容都行,这里用LPARAM存放,WPARAM 不用,设为NULL。所以也可以写成
pWnd->SendMessage(WM_MY_OWN_MSG,(WPARAM)uMsg,NULL);
不过一般是LPARAM传地址,WPARAM传其他参数。
虽然发送端已经向接收端发送WM_MY_OWN_MSG消息了,但是要想接收端识别并知道如何处理它还需要在接收端定义一遍这个消息(告诉接收端识别这个消息)并进行消息映射和实现消息映射函数(告诉接收端在收到这个消息后如何处理),所以在接收端:
①定义消息。在在xxxDlg.cpp(xxx为接收端工程名)头部定义自己的消息WM_MY_OWN_MSG(名字和发送端同)
#define WM_MY_OWN_MSG WM_USER + 100
②定义消息映射表。在BEGIN_MESSAGE_MAP(CRecieveMsgDlg, CDialog)
//{{AFX_MSG_MAP(CRecieveMsgDlg)
.........
//}}AFX_MSG_MAP
END_MESSAGE_MAP()之间添加WM_MY_OWN_MSG的消息映射
ON_MESSAGE(WM_MY_OWN_MSG,OnRecvUsermsg)即告诉程序收到WM_MY_OWN_MSG消息时交由OnRecvUsermsg函数处理。
③实现消息映射函数。用向CxxxDlg类(xxx为接收端工程名)添加成员函数。类型void,access为protected,函数描述
void OnRecvUsermsg(WPARAM wParam, LPARAM lParam)
实现为:
void CRecieveMsgDlg::OnRecvUsermsg(WPARAM wParam,LPARAM lParam)
{
CString szUsermsg;
szUsermsg.Format("%u",unsigned int(lParam));
CWnd::SetDlgItemText(IDC_RECV_USERMSG,szUsermsg);
}
这样接收端IDC_RECV_USERMSG中就可以显示发送端传过去的数了。
(2)另一种定义自己的消息的方法是使用RegisterWindowMessage注册新的消息。
和WM_USER+XXX的方法基本相同。还是发送接受端都要注册这个消息,接收端定义消息映射表实现消息映射函数。其优势是不用考虑定义的消息必须在WM_USER到0x7FFF之间这个限制。
发送端:
const UINT WM_MY_OWN_REG_MSG = ::RegisterWindowMessage("skq_reg_msg");
void CSendMessageDlg::OnSendRegmsg()
{
// TODO: Add your control notification handler code here
CString szRegMsg;
szRegMsg.Empty();
UINT uMsg;
CWnd::GetDlgItemText(IDC_EDIT_REGMSG,szRegMsg);
if(szRegMsg.IsEmpty())
{
CWnd::MessageBox("Please input sth");
return;
}
uMsg = atoi(szRegMsg);
CWnd *pWnd = CWnd::FindWindow(NULL,TEXT("RecieveMsg 进程间通信接收端"));
if(pWnd == NULL)
{
AfxMessageBox("Unable to find DataRecieve");
return;
}
pWnd->SendMessage(WM_MY_OWN_REG_MSG,NULL,(LPARAM)uMsg);
}
接收端:
①
UINT WM_MY_OWN_REG_MSG = ::RegisterWindowMessage("skq_reg_msg");
②在定义消息映射表时不能再用ON_MESSAGE宏了,要用
ON_REGISTERED_MESSAGE宏。
ON_REGISTERED_MESSAGE(WM_MY_OWN_REG_MSG,OnRecvRegmsg)
③实现消息映射函数
void CRecieveMsgDlg::OnRecvRegmsg(WPARAM wParam, LPARAM lParam)
{
CString szRegmsg;
szRegmsg.Format("%u",unsigned int(lParam));
CWnd::SetDlgItemText(IDC_RECV_REGMSG,szRegmsg);
}
自定义消息实现进程通信的局限
由于WM_XXX都是UINT类型,对于字符串或者大批量的数据,不能用此法通信
发消息一般有两种方式:SendMessage 和 PostMessage 。
其中SendMessage指发送消息并且等待结果返回后,主进程才继续运行;PostMessage指发送消息后不等待结果返回,主进程直接继续运行。
下面举例:如何在VC/MFC机制下发SendMessage消息,其实发PostMessage消息的方式和这是一样的。
//下面为发送用户自定义消息的方式:
//可以在头文件stdafx.h中定义用户消息
//定义用户消息,不可与系统消息冲突,所以就这样定义
#define WM_MYMESSAGE WM_USER+100 //WM+USER表示用户消息,加100还是加其他值并没多大区别的
//向主程序框架MainFrm发送消息
//SendMessage第二第三参数可以为其他更多的类型,不局限于此
AfxGetMainWnd()->SendMessage(WM_MYMESSAGE,true,2);
//在主程序框架MainFrm.cpp接收自定义的消息WM_MYMESSAGE
BEGIN_MESSAGE_MAP()
ON_MESSAGE(WM_MYMESSAGE, OnTestMessage)
END_MESSAGE_MAP()
//在主程序框架MainFrm中定义与实现消息处理函数OnTestMessage
//在MainFrm.h中定义如下:
//其中wParam接收SendMessage的第二个参数true,lParam接收第三个参数2
LRESULT OnTestMessage(WPARAM wParam, LPARAM lParam);
//在MainFrm.cpp中实现消息处理函数:
LRESULT CMainFrame::OnTestMessage(WPARAM wParam, LPARAM lParam)
{
// 添加你想要的代码 //
return 0L;
}
//下面为处理系统消息的方式
//在MyDialog.h中定义消息
afx_msg LRESULT OnMouseLeave(WPARAM, LPARAM);//响应鼠标离开事件
//在MyDialog.cpp中接收消息
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()
//响应鼠标离开事件
LRESULT CMyDialog::OnMouseLeave( WPARAM, LPARAM )
{
CPoint pt;
//WINAPI函数:获得鼠标当前位置
GetCursorPos(&pt);
CRect rect;
//WINAPI函数:获得当前对话框(窗口)的大小
GetWindowRect(&rect);
//判断鼠标是否当前窗口上,FALSE为不在
if(FALSE == PtInRect(&rect, pt))
{
AfxGetMainWnd()->SendMessage(WM_MYMESSAGE,true,2);
}
return 0;
}
PS:向其他类发送消息的实现方式是类似的,只是调用方式为:
CMyDialog dlg;
dlg.SendMessage();