【C#】C# Winform程序之间通讯
实现原理
通过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
猜你喜欢
- 【C#】Winform NanUI 0.88版本 JS和C#相互调用
- 目录一、需求版本二、实例JS调用C#注册的只读属性JS调用C#注册的字段JS调用C#注册的同步方法JS调用C#注册的异步方法C#注册一个方法,JS调用并传递参数C#注册一个方法,JS调用并接收C#返回值C#注册一个方法,接收JS的数组参数C#注册一个方法,接收JS的一个函数,执行这个JS函数,并将C#的值传递过去三、结束一、需求在软件的界面和软件逻辑分离后,最重要的就是要处理参数的传递,和函数的调用,因此存在JS中和C#相互调用的需求。版本NanUI 版本:0.8.80.191二、实例using
- 【C#】Winform解决方案打包成.exe 安装版Windows桌面应用程序
- 踩了几天的坑,慢慢爬出来了。帮助一下新手友人吧,高手请绕路。IDE Version:Visual Studio 20191.安装Microsoft Visual Studio Installer Project(1)打开Visual Studio 2019,扩展->管理扩展(2)搜索install,下载图中的扩展即可(我已经安装了,所以没有下载按钮)按照操作安装即可2.打包(1)右键 解决方案->添加->新建项目(2)搜索setup->选择 Setup Project-&
- 【C#】C# NLua Winform 热更新
- 一、概述NLua 是一个用于 .NET 平台的 Lua 脚本绑定库。它允许在 C# 代码中嵌入 Lua 脚本,并允许两者之间进行交互。NLua 的主要特点包括:轻量级:NLua 是一个轻量级的库,易于集成到现有的 .NET 项目中。动态类型:Lua 是动态类型的语言,这意味着变量的类型可以在运行时改变。灵活的绑定:NLua 提供了灵活的绑定机制,使得 C# 和 Lua 之间的数据交互变得简单。丰富的 API:NLua 提供了丰富的 API,以便在 Lua 脚本中调用 .NET 的类和方法。调试支
- 【C#】C#Windows桌面应用开发实践
- 速览必须功能一览简单下载异步下载如何解决下载文件不完整的问题使用 Downloader 进行 HTTP 多线程下载创建一个下载服务:下载非 HTTP 协议的文件注册表相关的操作(添加与删除)文件占用问题的处理防止重复启动只开一个实例,通用弹窗和提示 使用示例使用 C# 下载文件 (引用自使用 C# 下载文件的十八般武艺)常用接口示例必须功能一览注册表相关的操作(添加与删除) RegistryKey hkm
- 【C#】从零开始用C#写一个桌面应用程序(二)一个表白程序
- 恶搞表白小程序如何添加按钮,如何添加属性和事件请移步前文。基础操作第一步:新建窗口 在工具箱内找到label和button,拖到form上,设置它们的size属性,autosize属性,text属性。第二步:添加事件为了实现我们的效果,需要给三个按钮分别设计点击事件,鼠标移入事件,鼠标点下事件。分别为click,mouseenter,mousedown事件。第三步:实现移动逻辑this获取form对象,clientsize获取实时大小,使用随机数值,设置对应按钮位置。将对应
- 【C#】CSDK/IDE-VSCode 搭建 C# 开发环境
- 最近准备写 C# 的笔记总结专栏 bug 笔记本硬盘空间实在是不够用了 根本没有办法再安装一个 Visual Studio 集成开发环境了!!! 在学 Java 的过程中基本都是用记事本和命令提示符……再也不想经历了 &nbs
- 【C#】C# Winform 定时清理日志
- 一、前言在 Winform 开发中经常有这样的需求,在用户执行一些操作不正确时,需要将错误信息反馈给用户,比如:登录密码不正确,无法连接到服务器等,一般常见的用法有两个:1.弹框使用 MessageBox.Show("密码错误"); 这样的方式,弹框后,用户必须点击确定后才能执行下一步操作,给用户的体验并不是特别好。2.在界面中显示错误信息,定时清除如果是输入框,直接用 ErrorProvider 控件就行了。如果只是做一些简单的提示信息,那么就要定时清除
- 【C#】Winform NanUI 0.77版本 读取本地资源(扩展功能)
- 一、前言在NanUI官方的文档中,原本是有一个NanUI.FileResourceHandler的扩展包的,但现在官方已经无法下载了,现在只有0.88版本中有一个NanUI.LocalFileResource程序包,而0.77版本只剩下了一个读取嵌入式资源的程序包。关于NanUI:NanUI | .Net/.Net Core界面组件NanUI 0.7版正式发布 - 林选臣 - 博客园在扩展功能之前,请参考[资源处理器]-04 自定义资源处理器 - 知乎 ,我参考这个帖子进行扩展的,也不