【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#】C# Winform 日志系统
- 目录一、效果1.刷新日志效果2.单独日志的分类3.保存日志的样式二、概述三、日志系统API1.字段Debug.IsScrollingDebug.VersionDebug.LogMaxLenDebug.LogTitleDebug.IsConsoleShowLog2.方法Debug.Log(string)Debug.Log(string, params object[])Debug.Logs(string)Debug.Logs(string, params object[])Debug.LogSav
- 【C#】C#md5加密
- using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace mdstr { internal
- 【C#】从零开始用C#写一个桌面应用程序(二)一个表白程序
- 恶搞表白小程序如何添加按钮,如何添加属性和事件请移步前文。基础操作第一步:新建窗口 在工具箱内找到label和button,拖到form上,设置它们的size属性,autosize属性,text属性。第二步:添加事件为了实现我们的效果,需要给三个按钮分别设计点击事件,鼠标移入事件,鼠标点下事件。分别为click,mouseenter,mousedown事件。第三步:实现移动逻辑this获取form对象,clientsize获取实时大小,使用随机数值,设置对应按钮位置。将对应
- 【C#】C# Winfrom Chart 图表控件 柱状图、折线图
- 目录一、参考二、柱状图1.新建项目2.修改图表样式3.绑定数据4.删除Series1图例1)使用属性窗体删除2)使用代码删除5.自定义X轴的刻度值1)使用List绑定2)使用LabelStyle.Format绑定6.自定义Y轴的刻度值7.X轴刻度值显示不全的解决方法8.修改X Y刻度值的字体样式9.X轴刻度值旋转90°10.禁用Y轴刻度线11.去掉Y轴刻度值12.改变柱子的宽度13.设置网格线的颜色14.设置网格线的线型三、折线图1.图表设置2.绑定数据结束效果:一、参考c# Chart设置样式
- 【C#】C#Windows桌面应用开发实践
- 速览必须功能一览简单下载异步下载如何解决下载文件不完整的问题使用 Downloader 进行 HTTP 多线程下载创建一个下载服务:下载非 HTTP 协议的文件注册表相关的操作(添加与删除)文件占用问题的处理防止重复启动只开一个实例,通用弹窗和提示 使用示例使用 C# 下载文件 (引用自使用 C# 下载文件的十八般武艺)常用接口示例必须功能一览注册表相关的操作(添加与删除) RegistryKey hkm
- 【C#】C# Winform 文本面板带滚动条
- 在PC软件开发中经常有这样的需求,需要在一个固定大小的面板中显示一些内容,并且面板能上下拖动,将所有的内容完整的展示,有点类似网页上看新闻,如果要在 winfrom 中要如何实现的呢,下面就演示如何实现的吧效果:1.新建一个winform 项目,在界面中拖入一个Panel 将 panel1 的 AutoScroll 设置为 True2.再次拖入一个 Panel ,将高度拉长,这时就自动出现了滚动条,只是此时里面还没有任何内容,下面就在 panel2 中加入一点内容。
- 【C#】C# Winform 相册功能,图片缩放,拖拽,预览图分页
- 一、前言在一些项目中也会用到预览图片的功能,至于为什么有一个添加图片的按钮,是因为有些项目,比如视觉相关的项目,摄像头拍摄图片,然后显示在界面上,拍一次显示一张。另一个,就是分页功能,当预览图位置不够用时就会用到。当前软件的功能1.添加图片如果8个预览图都满了,会自动分页,就可以点击上一页,或者下一页了。2.点击预览图显示大图点击预览图,之前的拖拽和放大会自动复位3.大图可以拖拽,放大,缩小如果图片比较小,有这个功能就看到图片的更多细节了。4.图片倒序排列最后拍摄的图片,始终显示在前面,方便用户
- 【C#】Winform NanUI 0.77版本 JS和C#相互调用
- 目录一、导入插件二、常用方法三、C#和JS相互调用1.C# 调用JS2.JS调用C#方法3.完整版C#代码4.完整版JS代码结束一、导入插件用的NanUI版本0.77参考官方地址:https://docs.formium.net/zh-hans/tutorial/first-app.html二、常用方法基础代码:using NetDimension.NanUI; using NetDimension.NanUI.Browser; class MainW