进程的通信 - WM_COPYDATA
创始人
2024-02-07 00:17:25

在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯。其中使用SendMessage向另一进程发送WM_COPYDATA消息是一种比较经济实惠的方法。

WM_COPYDATA通信需要将传递的消息封装在COPYDATASTRUCT结构体中,在SendMessage消息传递函数时作为lParam参数传递

COPYDATASTRUCT的结构如下:

typedef struct tagCOPYDATASTRUCT {ULONG_PTR dwData;DWORD     cbData;PVOID     lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
  • 参数dwData

为自定义数据,按照自己习惯设置就好,不影响对象的传输;

  • 参数cbData

表示传递数据的大小(以字节为单位

  • 参数PVOID

表示传递的数据,是一个void*类型 

使用WM_COPYDATA时要用SendMessage而不能使用PostMessage,因为SendMessage是阻塞的,会等待消息响应窗体处理消息完毕后再返回;而PostMessage是异步的,这样就可能会导致当消息响应窗体接收到WM_COPYDATA的时候,COPYDATASTRUCT对象已经被析构了,导致访问数据发生异常。

LRESULT SendMessage([in] HWND   hWnd,[in] UINT   Msg,[in] WPARAM wParam,[in] LPARAM lParam
);
  • 参数hWnd

表示接收消息的窗体句柄

  • 参数Msg

指定附加的消息特定信息。在WM_COPYDATA进程通信中这个参数设置成WM_COPYDATA

  • 参数wParam

指定附加消息的特定信息。在WM_COPYDATA通信中这个参数设置为当前窗体的句柄

可以通过AfxGetApp()->m_pMainWnd获得,但需要强转成WPARAM

  • 参数lParam

指定附加消息的特定信息。在WM_COPYDATA通信中这个参数设置为COPYDATASTRUCT结构体,也需要强转成lParam

使用WM_COPYDATA进行进程间的通信需要提前获得另一个进程的窗体句柄。虽然spy++工具可以每次查到窗体的句柄,但是进程每次运行后句柄可能会改变,因此我们要先获得窗体的名称,再通过FindWindow函数获得窗体句柄

strWindowTitle是窗体的名称 

HWND FindWindowW([in, optional] LPCWSTR lpClassName,[in, optional] LPCWSTR lpWindowName
);
  • 参数lpClassName

一般设置为NULL

  • 参数lpWindowName

表示窗口的名称 

发送数据端 

返回值

函数成功,返回窗口的句柄

函数失败,返回NULL

在判断函数返回值时,不仅要判断返回的句柄是否为空,还需要判断句柄标识的是否是现有的窗口

通过调用IsWindow函数判断长提是否还存在

BOOL IsWindow([in, optional] HWND hWnd
);
  • 参数hWnd

表示窗口的句柄

返回值

如果窗口句柄标识现有窗口,则返回值非零

如果窗口句柄未标识现有窗口,则返回零 

接收端

接收端通过消息响应函数来接收数据

带xxxDlg文件中添加WM_COPYDATA消息响应函数

f667c983b13a40fe8acfc48d5831f73a.png

 当有消息发送过来时就会响应这个函数,

BOOL CWMCOPYDATADlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}

通过解析参数COPYDATASTRUCT* pCopyDataStruct就可以获得发送过来的数据了

需要注意的是

  1. 使用WM_COPYDATA时要用SendMessage而不能使用PostMessage,因为SendMessage是阻塞的,会等待消息响应窗体处理消息完毕后再返回;而PostMessage是异步的,这样就可能会导致当消息响应窗体接收到WM_COPYDATA的时候,COPYDATASTRUCT对象已经被析构了,导致访问数据发生异常。
  2. COPYDATA结构体的实质依然是共享内存,区别是这一片特殊的共享内存由操作系统管理而不用用户手动申请管理。
  3. WM_COPYDATA适合小数据量的进程间通信,大数据量可能造成内存问题,以及界面卡死,因为消息的发送形式是同步的。

Demo示例:

8f8d95b3a5a14d93811fe951cfe2c65c.png

374f1656e6ab44659da4532bea29dc9b.png

新建两个基于对话框的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);
}

运行结果:

11f8ab557e2048cea59d71e2d8f41ad8.gif 

右端进程点击发送,左端继承就会将接收到的数据显示出来,此时右端继承会进入阻塞状态,直到左边进程对消息做出处理。 

 

 

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...