实现原理
通过Windows系统中 User32.dll 中的 FindWindow 方法来寻找系统正在运行的程序句柄,通过 SendMessage 方法来发送消息,winform 中的 WndProc 方法来接收消息,下面是SendMessage,FindWindow 这两个参数的具体介绍:
1.SendMessage
该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。该函数是应用程序和应用程序之间进行消息传递的主要手段之一
函数原型:
IntPtr SendMessage(int hWnd, int msg, IntPtr wParam, IntPtr lParam);
参数
hWnd
其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口
Msg
指定被发送的消息
wParam
指定附加的消息指定信息
IParam
指定附加的消息指定信息
返回值
返回值指定消息处理的结果,依赖于所发送的消息
备注
需要用HWND_BROADCAST通信的应用程序应当使用函数RegisterWindowMessage来为应用程序间的通信取得一个唯一的消息。
2.FindWindow
函数获得一个顶层窗体的句柄,该窗体的类名和窗体名与给定的字符串相匹配。这个函数不查找子窗体。在查找时不区分大写和小写
函数原型
int FindWindow(string lpClassName, string lpWindowName);
参数
IpClassName
指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。假设该參数为一个成员,则它必须为前次调用theGlobafAddAtom函数产生的全局成员。该成员为16位,必须位于IpClassName的低 16位,高位必须为 0
IpWindowName
指向一个指定了窗体名(窗体标题)的空结束字符串。假设该參数为空,则为全部窗体全匹配
返回值
假设函数成功,返回值为具有指定类名和窗体名的窗体句柄;假设函数失败,返回值为NULL
下面的 Demo 是基于 .NET Framework 框架写的,经测试有效,但在最新的 .Net6 框架中,下面的代码无法收到消息,具体原因还不太清楚,有知道的大佬,欢迎留言告诉我。
程序1
界面:
代码:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace SendDemo1st
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public struct CopyDataStruct
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
public const int WM_COPYDATA = 0x004A;
//通过窗口标题来查找窗口句柄
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern int FindWindow(string lpClassName, string lpWindowName);
//在DLL库中的发送消息函数
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage
(
int hWnd, // 目标窗口的句柄
int Msg, // 在这里是WM_COPYDATA
int wParam, // 第一个消息参数
ref CopyDataStruct lParam // 第二个消息参数
);
//发送消息
private void button1_Click(object sender, EventArgs e)
{
string strURL = textBox1.Text;
CopyDataStruct cds;
cds.dwData = (IntPtr)1; //这里可以传入一些自定义的数据,但只能是4字节整数
cds.lpData = strURL; //消息字符串
cds.cbData = System.Text.Encoding.Default.GetBytes(strURL).Length + 1; //注意,这里的长度是按字节来算的
SendMessage(FindWindow(null, "Form2"), WM_COPYDATA, 0, ref cds); // 窗口标题
}
//接收消息方法
protected override void WndProc(ref System.Windows.Forms.Message e)
{
if (e.Msg == WM_COPYDATA)
{
CopyDataStruct cds = (CopyDataStruct)e.GetLParam(typeof(CopyDataStruct));
textBox2.Text = cds.lpData.ToString();
}
base.WndProc(ref e);
}
}
}
程序2
界面:
代码:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace SendDemo2nd
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public struct CopyDataStruct
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
public const int WM_COPYDATA = 0x004A;
//通过窗口标题来查找窗口句柄
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern int FindWindow(string lpClassName, string lpWindowName);
//在DLL库中的发送消息函数
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage
(
int hWnd, // 目标窗口的句柄
int Msg, // 在这里是WM_COPYDATA
int wParam, // 第一个消息参数
ref CopyDataStruct lParam // 第二个消息参数
);
private void button1_Click(object sender, EventArgs e)
{
string strURL = textBox1.Text;
CopyDataStruct cds;
cds.dwData = (IntPtr)1; //这里可以传入一些自定义的数据,但只能是4字节整数
cds.lpData = strURL; //消息字符串
cds.cbData = System.Text.Encoding.Default.GetBytes(strURL).Length + 1; //注意,这里的长度是按字节来算的
SendMessage(FindWindow(null, "Form1"), WM_COPYDATA, 0, ref cds); // 窗口标题
}
//接收消息方法
protected override void WndProc(ref System.Windows.Forms.Message e)
{
if (e.Msg == WM_COPYDATA)
{
CopyDataStruct cds = (CopyDataStruct)e.GetLParam(typeof(CopyDataStruct));
textBox2.Text = cds.lpData.ToString();
}
base.WndProc(ref e);
}
}
}
测试
运行两个程序,界面几乎没什么区别,下面测试下效果:
经过测试,发送消息,和接收消息都是正常可以使用的,但是WndProc这个方法只能运行在winfrom项目中,这也是个缺点。
结束
如果这个帖子对你有用,欢迎给我点赞 + 留言,谢谢
end