VC进程间通信之消息传递PostMessge()或SendMessage()

时间:2022-09-13 19:46:45


1.  进程内消息:

(1). 只传消息码

(2). 传送消息串

发送端:
void CTestDlg::OnBnClickedButtonSend()
{
	CString* msg = new CString("发送的字符串");
	::SendMessage(m_hWnd,WM_USER+1,0,(LPARAM)msg);
	delete msg;
}

接收端:
afx_msg HRESULT OnClickBtn(WPARAM,LPARAM);

BEGIN_MESSAGE_MAP
ON_MESSAGE(WM_USER+1,OnClickBtn)
END_MESSAGE_MAP()

HRESULT CSendMessageDlg::OnClickBtn1(WPARAM wParam,LPARAM lParam)
{
	CString* rmsg = (CString*)lParam;
	MessageBox(*rmsg);
	return TRUE;
}

 2.  进程间通讯:

PostMessge或者SendMessage()实现进程间通讯

(1)两个不同的进程不能用上面的方法,当然只发送消息不发内容是可以的。

(2)两个进程由于使用的是相互独立的两个虚拟内存空间,同一地址对不同的进程来说并不一定指向同一物理内存,内容也就不一定一样,因此不同进程无法通过传地址的方式传递字符串(但是同一进程下的不同线程是可以的)

2.解决办法

发送WM_COPYDATA消息在进程间传送数据

(1)发送消息

The exchange of data is performed by finding the other application (using FindWindow) and sending a WM_COPYDATA message to that window

使用FindWindow找到窗口,然后发送WM_COPYDATA消息,字符串附加到COPYDATASTRUCT 结构体

LRESULT copyDataResult;  //copyDataResult has value returned by other app 
CWnd *pOtherWnd = CWnd::FindWindow(NULL, strWindowTitle);

if (pOtherWnd)
{
	COPYDATASTRUCT cpd;
	cpd.dwData = 0;
	cpd.cbData = strDataToSend.GetLength();			 //data length
	cpd.lpData = (void*)strDataToSend.GetBuffer(cpd.cbData); //data buffer
	copyDataResult = pOtherWnd->SendMessage(WM_COPYDATA,(WPARAM)AfxGetApp()->m_pMainWnd->GetSafeHwnd(),(LPARAM)&cpd);
	strDataToSend.ReleaseBuffer();
}
else 
{
	AfxMessageBox("Unable to find other app.");
}

(2)添加消息

The other app should handle the WM_COPYDATA message in the following manner

BEGIN_MESSAGE_MAP(CMyWnd, CWnd)
...
ON_WM_COPYDATA()
...
END_MESSAGE_MAP()

(3)消息处理

BOOL CMyWnd::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
	CString strRecievedText = (LPCSTR) (pCopyDataStruct->lpData);
	return CMyWnd::OnCopyData(pWnd, pCopyDataStruct);
}

五、PostMessage  和SendMessage的区别

(1). PostMessage 和SendMessage的区别主要在于是否等待其他程序消息处理完成。

PostMessage只是把消息放入队列,不管其他程序是否处理都返回,然后继续执行。

而SendMessage则必须等待其他程序处理消息完成后才返回继续执行。由于SendMessage消息不放进消息队列, 所以PreTranslateMessage里无法收到其消息。

(2). 这两个函数的返回值也不同

原型:

BOOL        PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);

SendMessage的返回值表示其他程序消息处理函数的返回值(如return 10,  则long nRet = SendMessage(...) = 12)。

PostMessage的返回值仅表示PostMessage函数执行是否成功,成功返回非零,否则返回零。


举例如下(只传消息码):

方法1: PostMessge或者SendMessage()消息机制

项目1中发送消息:

#define WM_MYMESSAGE WM_USER + 1 

//目标进程的窗口类名(可通过Spy++工具查看)和窗口名 
CWnd *pWnd = CWnd::FindWindow("#32770", "MfcTest");
if (NULL != pWnd)
{
	pWnd->PostMessage(WM_MYMESSAGE, NULL, NULL);
}

或者:
HWND hWnd = ::FindWindow("#32770", "MfcTest");
if (NULL != hWnd)
{
	::PostMessage(hWnd, WM_MYMESSAGE, NULL, NULL);
}
项目2中接收消息:

.h中声明:

afx_msg LRESULT OnMyMessage(WPARAM wp, LPARAM lp);

.cpp中定义:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 
   ... 
   ON_MESSAGE(WM_MYMESSAGE, OnMyMessage) 
   ... 
END_MESSAGE_MAP() 

LRESULT CMfcTestDlg::OnMyMessage(WPARAM wp, LPARAM lp)
{ 
	AfxMessageBox("Hello World"); 
	return 0; 
}

说明:

使用PostMessage或SendMessage均可,区别在于SendMessage阻塞,直到目标窗口程序处理完消息再返回,而PostMessage是将一个消息寄送到一个线程的消息队列后就立即返回。通常使用PostMessage,如果为了探测目标进程是否存在,则用SendMessage比较好。


方法2: 消息接收端采用PreTranslateMessage()来处理

发送端代码:

#define WM_MYMESSAGE WM_USER + 1 

//目标进程的窗口类名(可通过Spy++工具查看)和窗口名 
CWnd *pWnd = CWnd::FindWindow("#32770", "MfcTest");
if (NULL != pWnd)
{
	pWnd->PostMessage(WM_MYMESSAGE, NULL, NULL);
}

或者:
HWND hWnd = ::FindWindow("#32770", "MfcTest");
if (NULL != hWnd)
{
	::PostMessage(hWnd, WM_MYMESSAGE, NULL, NULL);
}

接收端代码:

.h声明

BOOL CMfcTestDlg::PreTranslateMessage(MSG* pMsg);

.cpp定义

#define WM_MYMESSAGE WM_USER + 1 

BOOL CMfcTestDlg::PreTranslateMessage(MSG* pMsg)
{
	if (pMsg->message ==  WM_USER + 1)
	{
		AfxMessageBox("Hello World");
	}

	return CDialog::PreTranslateMessage(pMsg);
}


说明:

这里将接收端处理放在PreTranslateMessage 中, 因此发送端必须选择 PostMessage, 因为SendMessage消息不放进消息队列, PreTranslateMessage里不能收到这个消息。