1、简介

当应用程序将数据传递给另一个应用程序时发送此消息。
This message is sent when an application passes data to another application.

应用程序必须使用SendMessage函数来发送此消息,而不是PostMessage函数。传递的数据不得包含指向接收数据的应用程序无法访问的对象的指针或其他引用。在发送此消息时,所引用的数据不得被发送进程的另一个线程更改。

接收应用程序应将数据视为只读。在个人通讯装置参数仅该消息的处理过程中是有效的。接收应用程序不应释放pcds引用的内存。如果接收应用程序必须在SendMessage返回后访问数据,它必须将数据复制到本地缓冲区中。

通过消息实现进程间通信有如下两种方法:
(1)另一种是通过使用WM_COPYDATA消息进行进程间的通信。
(2)一种通过自定义消息进行进程间的通信.

2、WM_COPYDATA消息通信(C++)

2.1 功能描述

​https://docs.microsoft.com/en-us/previous-versions/aa928292(v=msdn.10)?redirectedfrom=MSDN​

WM_COPYDATA
wParam = (WPARAM)(HWND) hwnd;
lParam = (LPARAM)(PCOPYDATASTRUCT) pcds;

可以通过工具Spy++获取目标窗口的标题文本和窗口类名。

C++实现进程通信(WM_COPYDATA,MFC,C#)_进程通信

  • 发送端部分
LPCTSTR lpszString = ...;
COPYDATASTRUCT cds;
cds.dwData = 1; // can be anything
cds.cbData = sizeof(TCHAR) * (_tcslen(lpszString) + 1);
cds.lpData = lpszString;
SendMessage(hwnd, WM_COPYDATA, (WPARAM)hwnd, (LPARAM)(LPVOID)&cds);
  • 接收端部分
COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;
if (pcds->dwData == 1)
{
LPCTSTR lpszString = (LPCTSTR)(pcds->lpData);
// do something with lpszString...
}

2.2 发送端

//***********************************************************************
// Purpose: MFC实现WM_COPYDATA进程通信(发送端部分)
// Author: 爱看书的小沐
// Date: 2022-4-29
// Languages: VC++、MFC
// Platform: Visual Studio 2017
// OS: Win10 win64
// ***********************************************************************

void CDlgSendMessage::OnBnClickedButtonSend()
{
USES_CONVERSION;

CString strReceiveWndTitle;
CString strReceiveClassName;
CString strMsg;

GetDlgItemText(IDC_EDIT_WIN_NAME, strReceiveWndTitle);
GetDlgItemText(IDC_EDIT_CLASS_NAME, strReceiveClassName);
GetDlgItemText(IDC_EDIT_MSG, strMsg);

HRESULT hResult = 0;
HWND hWndReceive = ::FindWindow(strReceiveClassName.GetBuffer(), strReceiveWndTitle.GetBuffer());
if (hWndReceive != NULL && ::IsWindow(hWndReceive))
{
COPYDATASTRUCT cdsSend;
cdsSend.dwData = 0;
cdsSend.cbData = strMsg.GetLength() * sizeof(TCHAR);
cdsSend.lpData = (void*)strMsg.GetBuffer();
hResult = ::SendMessage(hWndReceive, WM_COPYDATA, (WPARAM)(AfxGetApp()->m_pMainWnd), (LPARAM)&cdsSend);
}

strReceiveWndTitle.ReleaseBuffer();
strReceiveClassName.ReleaseBuffer();
strMsg.ReleaseBuffer();
}

2.2 接收端

//***********************************************************************
// Purpose: MFC实现WM_COPYDATA进程通信(接收端部分)
// Author: 爱看书的小沐
// Date: 2022-4-29
// Languages: VC++、MFC
// Platform: Visual Studio 2017
// OS: Win10 win64
// ***********************************************************************

BEGIN_MESSAGE_MAP(CDlgSendMessage, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON_SEND, &CDlgSendMessage::OnBnClickedButtonSend)
ON_WM_CTLCOLOR()
ON_WM_COPYDATA()
END_MESSAGE_MAP()

BOOL CDlgSendMessage::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
if (pCopyDataStruct->cbData > 0)
{
TCHAR recvData[1024] = { 0 };
memcpy(recvData, (TCHAR*)pCopyDataStruct->lpData, pCopyDataStruct->cbData);
CString str;
str.Format(_T("%s"), recvData);
SetDlgItemText(IDC_EDIT_LOG, str);
}

return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}

运行界面截图如下:

C++实现进程通信(WM_COPYDATA,MFC,C#)_c++_02

3、WM_COPYDATA消息通信(C#)

3.1 结构体定义

CommonApi.cs:

//***********************************************************************
// Purpose: C#实现WM_COPYDATA进程通信(公共代码部分)
// Author: 爱看书的小沐
// Date: 2022-4-29
// Languages: C#
// Platform: Visual Studio 2017
// OS: Win10 win64
// ***********************************************************************

using System;
using System.Runtime.InteropServices;

namespace WindowsFormsApp4
{
public class CommonApi
{
[DllImport("user32.dll", EntryPoint = "FindWindow")]
public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hwnd, int msg, int wParam, ref COPYDATASTRUCT lParam);

public const int WM_COPYDATA = 0x004A;

/// <summary>
/// WM_COPYDATA消息,进程间传输信息的固定结构
/// </summary>
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;

[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
}

3.2 发送端

//***********************************************************************
// Purpose: C#实现WM_COPYDATA进程通信(发送端部分)
// Author: 爱看书的小沐
// Date: 2022-4-29
// Languages: C#
// Platform: Visual Studio 2017
// OS: Win10 win64
// ***********************************************************************

using System;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void btnSend_Click(object sender, EventArgs e)
{
string className = txtReceiveWinClass.Text;
string captionName = txtReceiveWinCaption.Text;
string message = txtMessage.Text;
IntPtr hWndReceive = CommonApi.FindWindow(className, captionName);

if (hWndReceive != IntPtr.Zero)
{
byte[] arr = Encoding.Default.GetBytes(message);
CommonApi.COPYDATASTRUCT cds;
cds.dwData = IntPtr.Zero;
cds.cbData = arr.Length + 1;
cds.lpData = message;

CommonApi.SendMessage(hWndReceive, CommonApi.WM_COPYDATA, 0, ref cds);
}
}
}
}

运行结果如下:

C++实现进程通信(WM_COPYDATA,MFC,C#)_copydata_03

3.3 接收端

//***********************************************************************
// Purpose: C#实现WM_COPYDATA进程通信(接收端部分)
// Author: 爱看书的小沐
// Date: 2022-4-29
// Languages: C#
// Platform: Visual Studio 2017
// OS: Win10 win64
// ***********************************************************************

using System;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

protected override void DefWndProc(ref System.Windows.Forms.Message message)
{
switch (message.Msg)
{
case CommonApi.WM_COPYDATA:
ReadCopyDataMessage(ref message);
break;
default:
base.DefWndProc(ref message);
break;
}
}

private void ReadCopyDataMessage(ref System.Windows.Forms.Message m)
{
CommonApi.COPYDATASTRUCT cdata = new CommonApi.COPYDATASTRUCT();
Type mytype = cdata.GetType();
cdata = (CommonApi.COPYDATASTRUCT)m.GetLParam(mytype);
string msg = cdata.lpData;
MessageBox.Show(msg);
}
}
}

运行结果如下:

C++实现进程通信(WM_COPYDATA,MFC,C#)_copydata_04


C++实现进程通信(WM_COPYDATA,MFC,C#)_网络通信_05

3、自定义消息通信

3.1 功能描述

消息分为两种,一种是系统已经定义的消息,另一种是用户自定义的消息。系统已经定义的消息是从0到0x3ff,用户自定义的消息可以从0x400开始。系统中提供了一个宏WM_USER,在进行自定义消息时,在WM_USER的基础上加一个值就可以了。

C++实现进程通信(WM_COPYDATA,MFC,C#)_网络通信_06

3.2 示例说明

#define WM_MY_MSG WM_USER + 1
afx_msg LRESULT OnUserAdo(WPARAM wParam, LPARAM lParam);
BEGIN_MESSAGE_MAP(CRenderView, CView)
ON_MESSAGE(WM_MY_MSG , OnUserAdo)
END_MESSAGE_MAP()
LRESULT CRenderView::OnUserAdo(WPARAM wParam, LPARAM lParam)
{
AdoDbParam* pParam = (AdoDbParam *)lParam;

return 0;
}

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进。o_O???
如果您需要相关功能的代码定制化开发,可以私聊留言作者。(✿◡‿◡)
感谢各位童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

C++实现进程通信(WM_COPYDATA,MFC,C#)_网络通信_07