进程间通信除了管道邮槽等高级方法外,还可以用自定义消息的方法来实现。
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类型,对于字符串或者大批量的数据,不能用此法通信