C#通过SendMessage消息来发送接收文本消息设定控件text
我们需要有消息循环的基础知识,如果你决定往下看,我假定你已经了解的消息循环的原理。所以本文没有详细的介绍消息循环的内容,所以我们从引入API开始。
一、引入user32.dll启用sendmessage
1、引入InteropServices
这里我们必须引入InteropServices,inter交互(托管代码和非托管代码之间的交互)op(operability)可操作性,InteropServices即为托管与非托管代码交互操作服务组件库。
为什么要用它呢,我们都知道C#是基于托管的代码,而C++的代码是属于非托管的,所以在C#中使用指针会使用关键字unsafe。
这里引入这个库,就是为了使用user32.dll基于c++的提供的API函数,如这里我们马上就要使用的SendMessage函数。
using System.Runtime.InteropServices;
[DllImport("User32.dll")]
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
2、定义数据包结构体
要使用SendMessage发送文本消息,可不能直接发送,因为这个函数没有一个参数是字符串类型的,也就是说,我们无可选择的只能简介去实现,只能附件在wParam或者lParam两个参数之一中。
而这种附加惭怍又必须依赖一种结构体:COPYDATASTRUCT。
在官方的文档中,我们可以查到,包含要通过 WM_COPYDATA 消息传递到另一个应用程序的数据。
public struct COPYDATASTRUCT{public IntPtr dwData; //可以是任意值public int cbData; //指定lpData内存区域的字节数[MarshalAs(UnmanagedType.LPStr)]public string lpData; //发送给目录窗口所在进程的数据}
3、Marshal
一个专门用于非托管内存的类
(1)、AllocCoTaskMem
SendMessage只能传递指针,那么我们收到的消息其实也是一个指针地址,收到这个地址后按照这个地址去找内存取出内容,这样就完成了文本消息的传递。所以我们首先要给文本分配一块内存.所以,这里我们使用AllocCoTaskMem,而且他的返回值为IntPtr。
public static IntPtr AllocCoTaskMem(int cb);
这里的参数cb,最好使用非托管的sizeof来计算大小更安全:Marshal.SizeOf(),如下使用:
IntPtr ptrData = Marshal.AllocCoTaskMem(Marshal.SizeOf(dataSize));
也可以考虑使用AllocHGlobal替代AllocCoTaskMem。
(2)、StructureToPtr
void StructureToPtr<T>([DisallowNull] T structure, IntPtr ptr, bool fDeleteOld);
作用:将附加数据的结构体实例的内容拷贝到指定的内存中去。
参数 说明见下表:
参数名 | 类型 | 描述 |
---|---|---|
structure | Object | 包含要封送的数据的托管对象。 该对象必须是格式化类的结构或实例。 |
ptr | IntPtr | 指向非托管内存块的指针,必须在调用此方法之前分配该指针。 |
fDeleteOld | Boolean | 如果在此方法复制该数据前在 DestroyStructure(IntPtr, Type) 参数上调用 ptr,则为 true。 |
可以参考官方:官方实例 |
(3)、FreeCoTaskMem
这个方法专门配合AllocCoTaskMem使用,在AllocCoTaskMem使用完后帮助其释放内存。
当我们前面分配内存使用的是AllocHGlobal我们就要用FreeHGlobal来释放内存。
4、发送SendMessage
发送消息必须准备齐SendMessage必须的四个参数,我们来看看这个方法
IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
我将四个参数的详细情况列表如下:
参数名 | 类型 | 说明 |
---|---|---|
hWnd | IntPtr | 最终接受该消息窗口的句柄。也就是说,哪个窗口接受就填写哪个窗口的句柄。0xffff ,则会将消息发送到系统中的所有顶级窗口 ,包括已禁用或不可见的未所有者窗口、重叠窗口和弹出窗口; |
Msg | unit | 要发送消息的,如这里要发送附加消息则用WM_COPYDATA对应的值为0x004A |
wParam | IntPtr | 其他的消息特定信息。如附加消息 |
lParam | IntPtr | 其他的消息特定信息。如附加消息 |
C#中药使用sendMessage就要使用要非安全代码,就要使用指针获得IntPtr,所以我们就要用到前面说道的AllocCoTaskMem来分配内存建立指针ptr,然后用StructureToPtr将附加数据的结构体实例的内容拷贝到ptr中。
IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(cds));Marshal.StructureToPtr(cds, ptr, false);
5、接收
接收端我们必须从LParam中重新按照前面定义的数据结构重新取回结构体中的数据部分,即lpData。所以有两件事要做。
1.利用类型转换获取COPYDATASTRUCT结构体类型数据
首先是利用方法GetType获取类型,关于这个函数的使用我在前的博文《C#反射机制的应用》中已经详细介绍过,不太清楚的可以点进去参考一下。
// 摘要:// Gets the System.Type of the current instance.//// 返回结果:// The exact runtime type of the current instance.public Type GetType();
这个方法很显然返回的就是实例的类型。
2、GetLParam
// 摘要:
// Gets the System.Windows.Forms.Message.LParam value and converts the value to
// an object.
//
// 参数:
// cls:
// The type to use to create an instance. This type must be declared as a structure
// type.
//
// 返回结果:
// An System.Object that represents an instance of the class specified by the cls
// parameter, with the data from the System.Windows.Forms.Message.LParam field of
// the message.
public object? GetLParam(Type cls);
这个函数很专业,因为太专用了,有三点可以说的:
1、参数cls,名称就表示declared structure,
2、参数而且必须是结构体类型。
3、返回的值是一个object,意思明白着让你进行一次类型转换(转回结构体呗)
COPYDATASTRUCT cdata = new COPYDATASTRUCT();Type mytype = cdata.GetType();cdata = (COPYDATASTRUCT)m.GetLParam(mytype)!;string str = cdata.lpData;
释放由非托管 COM 任务内存分配器分配的内存块。
二、给控件设定text
1、准备一个发送接收环境
这一步其实是最简单的,那就是设置一个发送控件一个文本框,用文本框来接收发送过来的消息:
红色边框的控件是自定义控件,便于我们从中发送消息,当然你也可以用一个按钮来替代。
2、发送代码
你可以在某个事件中调用下面的方法,即可完成发送文字消息。
void sendText(string str)
{try{string data = str;COPYDATASTRUCT cds = new COPYDATASTRUCT();cds.dwData = (IntPtr)Marshal.SizeOf(cds);cds.cbData = data.Length + 1;cds.lpData = data;IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(cds));Marshal.StructureToPtr(cds, ptr, false);SendMessage((IntPtr)0xffff, 0x004A, IntPtr.Zero, ptr);}finally{Marshal.AllocCoTaskMem(ptr);}}
3、接收代码
在哪里接收记得,上面的SendMessage的第一个参数就要写相应的句柄,我这里写的oxffff是对所有顶级窗体广播。所以在我们的主窗体中是肯定能够收到的。可以选择在WndProc或者DefWndProc都是可以的。
protected override void DefWndProc(ref System.Windows.Forms.Message m){switch (m.Msg)case WM_COPYDATA:{COPYDATASTRUCT cdata = new COPYDATASTRUCT();Type mytype = cdata.GetType();cdata = (COPYDATASTRUCT)m.GetLParam(mytype)!;string str = cdata.lpData;textBox1.Text = str;break;}default:base.DefWndProc(ref m);//调用基类函数处理非自定义消息。break;}}
4、运行效果
发送控件变蓝色说明被点击,我们可以看到弹出了消息对话框,同时接受控件文本框内已经被消息驱动设定为我们收到的消息文本。
三、官网参考链接
https://learn.microsoft.com/zh-cn/windows/win32/dataxchg/using-data-copy
https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-messages-and-message-queues
C#通过SendMessage消息来发送接收文本消息设定控件text相关推荐
- 微信公众号生成文本到服务器,使用Golang开发微信公众平台-接收文本消息
一旦接入验证成功,成为正式开发者,你可能会迫不及待地想通过手机微信发送一条"Hello, Wechat"到你的公众号服务器.不过上一篇的那个程序还无法处理手机提交的文本消息,本篇将 ...
- 【苹果家庭群发推送】软件安装最新的Appletweetios.macosimessage是用于发送Apple文本消息
推荐内容IMESSGAE相关 作者推荐内容 iMessage苹果推软件 *** 点击即可查看作者要求内容信息 作者推荐内容 1.家庭推内容 *** 点击即可查看作者要求内容信息 作者推荐内容 2.相册 ...
- Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理
在前几节文章中我们讲述了微信公众号环境的搭建.如何接入微信公众平台.以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装:接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这 ...
- KAFKA SpringBoot2 Nacos 消息异步发送和消费消息(进阶篇)
文章目录 一.基础集成 1. 技术选型 2. 导入依赖 3. kafka配置 4. auto-offset-reset 简述 5. 新增一个订单类 6. 生产者(异步) 7. 消费者 8. kafka ...
- Android 手机卫士--解析json与消息机制发送不同类型消息
本文地址:http://www.cnblogs.com/wuyudong/p/5900800.html,转载请注明源地址. 1.解析json数据 解析json的代码很简单 JSONObject jso ...
- 【转】C# 实现用艺术效果显示文本的标签控件
C# 实现用艺术效果显示文本的标签控件 2009-09-28 来自:CS 程序员之窗 摘要:C#实现边框.浮雕.印版效果显示文字的标签控件,可以改变边框的宽度和文字边框的颜色,实现绚丽的文字显示效果 ...
- 将鼠标消息发送给指定的父控件_勾子
以下类通过挂载勾子原理,实现将子控件鼠标消息发送给父控件. 调用: MousePreview mp=new MousePreview(pControl); //pControl为父控件 //启用勾子 ...
- #304 – 为没有文本标题的控件定义Access 键(Defining an Access Key That Gives Focus to a Different Control)
有些控件,并没有自己的文本标题,他们可以通过与之相邻的Label来定义自己的Access 键.通过Access 键,他们可以获得输入焦点. 下面的例子中,在"Enter Name" ...
- MFC_C++02_模态对话框,非模态对话框,StaticText静态文本,CEditCtrl控件,ComboBox下拉框,CListCtrl控件,CTreeCtrl 树控件,TabCtrl标签控件
01 模态对话框创建 更改标题名: 菜单栏 --> 视图->工具箱 ,找到工具箱 导入两个按钮: 准备对话框: 插入就可以了,更改名称 双击按钮,可以进入点击事件 创建控件的类:右击-&g ...
最新文章
- 在SQL Server中如何转化长日期形式为短日期格式
- 推荐系统产品与算法概述 | 深度
- Azure Stack-1807 版本 配置10分钟、自动部署6小时-我的ASDK第7次实践
- 如何安装nginx_lua_module模块
- [JSConf EU 2018] 大脑控制 Javascript
- matlab幂次变换代码,常用的一些图像处理Matlab源代码
- kafka python client:PyKafka vs kafka-python
- Selenium2 + Python3.6实战(五):生成HTML测试报告 Invalid argument
- 用大前端技术实现的一款仿Boss直聘app(已开源)
- angular集成websocket_angular使用 websocket,少点套路,多一点真诚
- 基于微信小程序的AI智能识物
- 2017大一计算机教程,2017年计算机等考一级章节考点:WPS2000新手入门教程
- win7 安装英文语言包
- AttributeError: module 'ahocorasick' has no attribute 'Automaton'解决
- 萌新入坑第一课——如何写技术博客
- 电脑怎么设置开机密码?简单几步给你的电脑“上锁”
- C/C++语言入门——鸡兔同笼问题
- Android 高德地图中路线规划绘制界面线路
- 压力传感器中英文术语对照表
- 大众点评超详细爬虫系列2
热门文章
- 世界上没有哪一份工作是不受气的
- 电子版微积分教课书,作者是怎样精心撰写的?
- Unity配置文件xxx.ini
- C语言笔记 | 一元三次方程
- k8s部署springcloud架构的一些心得体会
- Flask asyncio 异步处理请求
- 《Unity Shader入门精要》笔记01 前言
- 计算机怎样设置开机音乐,电脑开机声音听腻了怎么办?一招教你搞定
- 小米最新系统android 10,小米MIUI 12再更新,基于Android 10的系统也来了,5项改变...
- 安卓手机玩游戏卡顿怎么解决_解决安卓手机卡顿反应慢的9个技巧