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++擷取目标視窗的标題文本和視窗類名。

- 發送端部分
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);
}
運作界面截圖如下:
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);
}
}
}
}
運作結果如下:
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);
}
}
}
運作結果如下:
3、自定義消息通信
3.1 功能描述
消息分為兩種,一種是系統已經定義的消息,另一種是使用者自定義的消息。系統已經定義的消息是從0到0x3ff,使用者自定義的消息可以從0x400開始。系統中提供了一個宏WM_USER,在進行自定義消息時,在WM_USER的基礎上加一個值就可以了。
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;
}