消息是Windows提供的一种驱动机制。对于进程间的通信,一般采用用户自定义的消息来完成进程间的通信,也可以使用windows定义的消息。如何实现一个程序向另外一个程序来发送消息来实现两个程序之间的通信呢?
在实现进程通信之前,首先要规定进程之间都具有唯一的消息标识,这个消息标识可以是自定义的消息或者是windows自定义的消息,这个消息标识必须是进程之间同一个标识。之后可以用SendMessage或者PostMessage来发送消息。发送消息的时候必须得指定一个窗口的句柄,这个句柄可以通过FindWindow或者FindWindowEx来获得,FindWindow是获取一个顶层窗口的句柄,而FindWindowEx是获取一个子窗口的句柄。
Postmessage和SendMessage是有区别的。PostMessage是把消息仍在消息队列后就返回,而SendMessage要一直等到消息被处理才返回。也就是说,用SendMessage实现的是类似与同步处理的操作。
HWND FindWindow(
LPCTSTR lpClassName, //类名
LPCTSTR lpWindowName //窗口的名字
);
MSDN:This function retrieves the handle to the top-level window whose class name and window name match the specified strings. This function does not search child windows.
HWND FindWindowEx(
HWND hwndParent,//父窗口
HWND hwndChildAfter,//从这个句柄的下一个窗口开始查找,必须是直接子窗口
LPCTSTR lpszClass,//类名
LPCTSTR lpszWindow//窗口的名字
);
MSDN: The FindWindowEx function retrieves a handle to a window whose class name and window name match the specified strings. The function searches child windows, beginning with the one following the specified child window. This function does not perform a case-sensitive search.
举一个很简单的例子:
在发送端,发送一个消息通知接收端进行某种操作,或者是发送一写参数给接收端。在发送端取出某个编辑框中的数字发送给接收端:
int number;
number = GetDlgItemInt(IDC_EDIT1);
CWnd *pwnd = CWnd::FindWindow(NULL,_T("Recv"));
if(pwnd != NULL)
{
::PostMessage(pwnd->m_hWnd,WM_EDITMESSAGE,WPARAM(number),NULL);
}
在接收端:
HRESULT CRecvDlg::OnCopyFrom(WPARAM wParam,LPARAM lParam)
{
SetDlgItemInt(IDC_EDIT1,int(wParam));
return 1;
}
其中OnCopyFrom是在客户端自定义的消息:
#define WM_EDITMESSAGE WM_USER+100
afx_msg HRESULT OnCopyFrom(WPARAM wParam,LPARAM lParam);
ON_MESSAGE(WM_EDITMESSAGE,OnCopyFrom)
这种实现进程通信的消息机制很少用来进行大量的参数传递,一般是进行一些事件通知,事件激发等等。这种机制只能是运行在Windows的操作系统上,而且必须知道接收窗口的窗口类名或者窗口名字,具有一定的局限性。
利用消息机制一个具有较好的应用的消息是WM_COPYDATA,这个消息能够实现进程之间数据的传递,在接收端重载WM_COPYDATA,有一个结构体进行数据传递PCOPYDATASTRUCT:
typedef struct tagCOPYDATASTRUCT {
DWORD dwData;
DWORD cbData;
PVOID lpData;
} COPYDATASTRUCT;
MSDN: This structure contains data to be passed to another application by the WM_COPYDATA message.
在发送端:
CString str;
GetDlgItemText(IDC_EDIT2,str);
CWnd *pwnd = CWnd::FindWindow(NULL,_T("Recv"));
if(pwnd != NULL)
{
COPYDATASTRUCT cp;
cp.cbData = str.GetLength()*2+1;
cp.dwData = 0;
cp.lpData = (PVOID)str.GetBuffer();
::SendMessage(pwnd->m_hWnd,WM_COPYDATA,(WPARAM)pwnd->m_hWnd,(LPARAM)&cp);
str.ReleaseBuffer();
}
接收端:
TCHAR * ch = new TCHAR[pCopyDataStruct->cbData];
memcpy(ch,pCopyDataStruct->lpData,pCopyDataStruct->cbData);
SetDlgItemText(IDC_EDIT2,(CString)ch);