赞
踩
在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯。其中使用SendMessage向另一进程发送WM_COPYDATA消息是一种比较经济实惠的方法。
WM_COPYDATA通信需要将传递的消息封装在COPYDATASTRUCT结构体中,在SendMessage消息传递函数时作为lParam参数传递
COPYDATASTRUCT的结构如下:
- typedef struct tagCOPYDATASTRUCT {
- ULONG_PTR dwData;
- DWORD cbData;
- PVOID lpData;
- } COPYDATASTRUCT, *PCOPYDATASTRUCT;
为自定义数据,按照自己习惯设置就好,不影响对象的传输;
表示传递数据的大小(以字节为单位
表示传递的数据,是一个void*类型
使用WM_COPYDATA时要用SendMessage而不能使用PostMessage,因为SendMessage是阻塞的,会等待消息响应窗体处理消息完毕后再返回;而PostMessage是异步的,这样就可能会导致当消息响应窗体接收到WM_COPYDATA的时候,COPYDATASTRUCT对象已经被析构了,导致访问数据发生异常。
- LRESULT SendMessage(
- [in] HWND hWnd,
- [in] UINT Msg,
- [in] WPARAM wParam,
- [in] LPARAM lParam
- );
表示接收消息的窗体句柄
指定附加的消息特定信息。在WM_COPYDATA进程通信中这个参数设置成WM_COPYDATA
指定附加消息的特定信息。在WM_COPYDATA通信中这个参数设置为当前窗体的句柄
可以通过AfxGetApp()->m_pMainWnd获得,但需要强转成WPARAM
指定附加消息的特定信息。在WM_COPYDATA通信中这个参数设置为COPYDATASTRUCT结构体,也需要强转成lParam
使用WM_COPYDATA进行进程间的通信需要提前获得另一个进程的窗体句柄。虽然spy++工具可以每次查到窗体的句柄,但是进程每次运行后句柄可能会改变,因此我们要先获得窗体的名称,再通过FindWindow函数获得窗体句柄
strWindowTitle是窗体的名称
- HWND FindWindowW(
- [in, optional] LPCWSTR lpClassName,
- [in, optional] LPCWSTR lpWindowName
- );
一般设置为NULL
表示窗口的名称
发送数据端
返回值
函数成功,返回窗口的句柄
函数失败,返回NULL
在判断函数返回值时,不仅要判断返回的句柄是否为空,还需要判断句柄标识的是否是现有的窗口
通过调用IsWindow函数判断长提是否还存在
- BOOL IsWindow(
- [in, optional] HWND hWnd
- );
表示窗口的句柄
返回值
如果窗口句柄标识现有窗口,则返回值非零
如果窗口句柄未标识现有窗口,则返回零
接收端
接收端通过消息响应函数来接收数据
带xxxDlg文件中添加WM_COPYDATA消息响应函数
当有消息发送过来时就会响应这个函数,
- BOOL CWMCOPYDATADlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
- {
- return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
- }
通过解析参数COPYDATASTRUCT* pCopyDataStruct就可以获得发送过来的数据了
需要注意的是
新建两个基于对话框的MFC应用,将其中一个窗体名称定为“MFCRecv”,当点击第二个应用的发送按钮后,会向第一个应用发送一段数据,第一个应用会将消息通过消息框显示出来 。
- CString strWindowTitle = _T("MFCRecv");
- HWND hRecvWnd = ::FindWindow(NULL, strWindowTitle.GetBuffer(0));
-
- CString strDataToSend = _T("Hello,这是霸道小明");
-
- if (hRecvWnd != NULL && ::IsWindow(hRecvWnd)) {
- //如果不是空,并且是一个窗口
-
- //数据的封装
- COPYDATASTRUCT cpd;
- cpd.dwData = 0;//要传递给应用程序的数据
- cpd.cbData = strDataToSend.GetLength() * sizeof(TCHAR);//传递数据的大小
- cpd.lpData = (PVOID)strDataToSend.GetBuffer(0);
- //AfxGetApp函数可以
- ::SendMessage(hRecvWnd, WM_COPYDATA, (WPARAM)(AfxGetApp()->m_pMainWnd), (LPARAM)&cpd);
- }
- strDataToSend.ReleaseBuffer();
- //消息响应函数
- BOOL CWMCOPYDATADlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
- {
- //窗口接收到消息,就会响应这个函数
- //解析数据
- LPCTSTR szText = (LPCTSTR)(pCopyDataStruct->lpData);
- DWORD dwLength = (DWORD)pCopyDataStruct->cbData;
- TCHAR szRecvText[1024] = { 0 };
- memcpy(szRecvText, szText, dwLength);
- MessageBox(szRecvText, _T("收到消息"), MB_OK);
- return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
- }
运行结果:
右端进程点击发送,左端继承就会将接收到的数据显示出来,此时右端继承会进入阻塞状态,直到左边进程对消息做出处理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。