功能概述
这段代码定义了一个名为WinIPC
的静态类,该类主要用于Windows进程间通信(IPC)。以下是其主要功能:
-
发送和接收消息:
WinIPC
类使用Windows消息(特别是WM_COPYDATA
消息)在进程之间发送和接收数据。这是通过SendMessageW
和FindWindowExW
这两个Windows API函数实现的,这两个函数通过DllImport
属性导入自user32.dll
。 -
检查应用程序是否正在运行:
IsRunning
方法检查具有特定应用程序ID的应用程序是否正在运行。它通过查找窗口标题为@MRW[{applicationId}]
的窗口来实现这一点。 -
异步发送消息:
SendMessageAsync
方法异步发送消息到具有特定应用程序ID的应用程序。它创建一个任务来发送消息,并在完成后返回任务的结果。 -
处理接收到的消息:当接收到
WM_COPYDATA
消息时,MessageReceiveWindow
类的WndProc
方法会调用OnMessageReceived
方法来处理消息。这个方法会从消息中提取数据,并触发MessageReceived
事件。 -
管理接收消息的窗口:
MessageReceiveWindow
类是一个不可见的窗口,用于接收WM_COPYDATA
消息。它是一个单例,可以通过GetInstance
方法获取实例。 -
数据结构:
CopyDataStruct
结构用于在进程之间传输数据。它包含一个指向数据的指针和数据的大小。
使用方法
检查应用程序是否正在运行
首先,可以使用IsRunning
方法来检查具有特定应用程序ID的应用程序是否正在运行。例如:
bool isRunning = WinIPC.IsRunning("MyApp");
如果应用程序正在运行,IsRunning
方法将返回true
;否则,它将返回false
。
发送消息
可以使用SendMessageAsync
方法来异步发送消息到具有特定应用程序ID的应用程序。例如:
byte[] message = Encoding.UTF8.GetBytes("Hello, world!");
bool success = await WinIPC.SendMessageAsync("MyApp", message);
这段代码将异步发送一个"Hello, world!"的消息到"MyApp"应用程序。如果消息发送成功,SendMessageAsync
方法将返回true
;否则,它将返回false
。
接收消息
可以通过订阅MessageReceived
事件来接收消息。例如:
WinIPC.MessageReceived += (sender, data) => {
string message = Encoding.UTF8.GetString(data);
MessageBox.Show($"Received message: {message}");
};
上面代码会在接收到消息时弹窗显示消息内容。
完整实现代码
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinForms
{
static class WinIPC
{
const int WM_COPYDATA = 0x004a;
[DllImport("user32.dll")]
private extern static IntPtr SendMessageW(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private extern static IntPtr FindWindowExW(IntPtr hWndParent, IntPtr hWndChildAfter, [MarshalAs(UnmanagedType.LPWStr)] string windowClassName, [MarshalAs(UnmanagedType.LPWStr)] string windowTitle);
public static event EventHandler<byte[]> MessageReceived;
public static bool IsRunning(string applicationId)
{
if (!Application.MessageLoop)
{
throw new InvalidOperationException("This method cannot be called on a thread that has not run a message loop.");
}
if (string.IsNullOrWhiteSpace(applicationId))
{
throw new ArgumentException($"The parameter {nameof(applicationId)} cannot be a blank string.");
}
IntPtr targetHwnd = FindWindowExW(IntPtr.Zero, IntPtr.Zero, null, $"@MRW[{applicationId}]");
if (targetHwnd != IntPtr.Zero)
{
return (true);
}
MessageReceiveWindow.GetInstance(applicationId);
return (false);
}
public static Task<bool> SendMessageAsync (string receiverApplicationId, byte[] message)
{
var tr = Task.Run(() => {
try
{
IntPtr hwnd = FindWindowExW(IntPtr.Zero, IntPtr.Zero, null, $"@MRW[{receiverApplicationId}]");
if (hwnd == IntPtr.Zero)
{
return (false);
}
IntPtr messageBuffer = Marshal.AllocHGlobal(message.Length);
Marshal.Copy(message, 0, messageBuffer, message.Length);
CopyDataStruct cds = new CopyDataStruct();
cds.cbData = message.Length;
cds.lpData = messageBuffer;
IntPtr dataStructBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(cds));
Marshal.StructureToPtr<CopyDataStruct>(cds, dataStructBuffer, true);
IntPtr result = SendMessageW(hwnd, WM_COPYDATA, IntPtr.Zero, dataStructBuffer);
Marshal.FreeHGlobal(dataStructBuffer);
Marshal.FreeHGlobal(messageBuffer);
return (result != IntPtr.Zero);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return (false);
}
});
return (tr);
}
private static void OnMessageReceived(IntPtr senderHWND, CopyDataStruct cds)
{
try
{
if (!(MessageReceived is null))
{
byte[] data = new byte[cds.cbData];
Marshal.Copy(cds.lpData, data, 0, cds.cbData);
MessageReceived?.Invoke(senderHWND, data);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
class MessageReceiveWindow : Form
{
private static MessageReceiveWindow MessageReceiveWindowInstance = null;
private MessageReceiveWindow()
{
this.Visible = false;
this.Enabled = false;
this.VisibleChanged += (_s, _e) => { if (this.Visible) this.Visible = false; };
}
public static MessageReceiveWindow GetInstance(string windowTitle = null)
{
if (MessageReceiveWindowInstance is null)
{
MessageReceiveWindowInstance = new MessageReceiveWindow();
MessageReceiveWindowInstance.Show();
}
MessageReceiveWindowInstance.Text = $"@MRW[{windowTitle}]";
return (MessageReceiveWindowInstance);
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_COPYDATA:
CopyDataStruct cds = Marshal.PtrToStructure<CopyDataStruct>(m.LParam);
WinIPC.OnMessageReceived(m.WParam, cds);
m.Result = new IntPtr(1);
return;
break;
default:
break;
}
base.WndProc(ref m);
}
}
[StructLayout(LayoutKind.Sequential)]
struct CopyDataStruct
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
}
}
知乎: @张赐荣
赐荣博客: www.prc.cx
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战