Windows进程间通信:WM_COPYDATA 实现笔记
一、核心数据结构:COPYDATASTRUCT
1 2 3 4 5
| typedef struct tagCOPYDATASTRUCT { ULONG_PTR dwData; DWORD cbData; PVOID lpData; } COPYDATASTRUCT, *PCOPYDATASTRUCT;
|
二、通信原理
- 查找目标窗口:发送方通过窗口标题获取接收方窗口句柄(
FindWindow)
- 封装与发送:发送方将数据封装为
COPYDATASTRUCT,通过 ::SendMessage() 发送 WM_COPYDATA 消息
- 系统调度与接收:Windows 操作系统根据窗口句柄将消息路由到目标窗口,调用其
OnCopyData() 回调函数
三、发送方实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| void CWMCOPYDATASenderDlg::OnBnClickedButtonSend() { CString strWindowTitle(_T("接收方")); CString strMsg(_T("我是发送方"));
HWND hWnd = ::FindWindow(NULL, strWindowTitle); if (hWnd != INVALID_HANDLE_VALUE && IsWindow(hWnd)) { COPYDATASTRUCT copyDataStruct; copyDataStruct.dwData = 0; copyDataStruct.cbData = strMsg.GetLength() * sizeof(TCHAR); copyDataStruct.lpData = (PVOID)strMsg.GetString();
::SendMessage(hWnd, WM_COPYDATA, (WPARAM)(AfxGetApp()->m_pMainWnd), (LPARAM)©DataStruct); } }
|
四、接收方实现
添加消息映射(两种方式)
方式一(推荐):在接收方对话框设计窗口 → 右键 → 类向导 → 消息 → 选择 WM_COPYDATA → 双击自动生成
方式二:手动添加消息映射宏
1 2 3 4 5 6 7
| afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);
BEGIN_MESSAGE_MAP(CWMCOPYDATARecverDlg, CDialogEx) ON_WM_COPYDATA() END_MESSAGE_MAP()
|
接收处理函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| BOOL CWMCOPYDATARecverDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) { LPCTSTR szData = (LPCTSTR)(pCopyDataStruct->lpData); DWORD dwLength = (DWORD)pCopyDataStruct->cbData; TCHAR szRecvText[1024] = { 0 }; memcpy(szRecvText, szData, dwLength); MessageBox(szRecvText, _T("消息接收"), MB_OK); return CDialogEx::OnCopyData(pWnd, pCopyDataStruct); }
|
五、关键注意事项
| 要点 |
说明 |
| 线程安全 |
建议使用 SendMessage(阻塞直到接收方处理完成),PostMessage 可能导致数据被提前释放 |
| Unicode/ANSI |
使用 TCHAR 系列保证字符集兼容,计算大小时务必包含 sizeof(TCHAR) 因子 |
| 数据生命周期 |
lpData 指向的数据在消息处理期间必须有效(发送方栈上或堆上均可) |
| 窗口查找 |
确保窗口标题精确匹配,可通过 Spy++ 工具验证 |
| 错误处理 |
检查 FindWindow 返回值及 IsWindow 有效性 |
六、适用场景
- ✅ 轻量级、低频率的进程间数据交换
- ✅ 同机进程通信(不支持跨机器)
- ✅ 自定义结构体或字符串传递
- ❌ 不适合大数据量或高频通信(有性能开销)
WM_COPY_DATA 封装数据和解析数据。非常方便。如果数据量大,建议用命名管道。