我们需要有消息循环的基础知识,如果你决定往下看,我假定你已经了解的消息循环的原理。所以本文没有详细的介绍消息循环的内容,所以我们从引入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相关推荐

  1. 微信公众号生成文本到服务器,使用Golang开发微信公众平台-接收文本消息

    一旦接入验证成功,成为正式开发者,你可能会迫不及待地想通过手机微信发送一条"Hello, Wechat"到你的公众号服务器.不过上一篇的那个程序还无法处理手机提交的文本消息,本篇将 ...

  2. 【苹果家庭群发推送】软件安装最新的Appletweetios.macosimessage是用于发送Apple文本消息

    推荐内容IMESSGAE相关 作者推荐内容 iMessage苹果推软件 *** 点击即可查看作者要求内容信息 作者推荐内容 1.家庭推内容 *** 点击即可查看作者要求内容信息 作者推荐内容 2.相册 ...

  3. Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

    在前几节文章中我们讲述了微信公众号环境的搭建.如何接入微信公众平台.以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装:接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这 ...

  4. KAFKA SpringBoot2 Nacos 消息异步发送和消费消息(进阶篇)

    文章目录 一.基础集成 1. 技术选型 2. 导入依赖 3. kafka配置 4. auto-offset-reset 简述 5. 新增一个订单类 6. 生产者(异步) 7. 消费者 8. kafka ...

  5. Android 手机卫士--解析json与消息机制发送不同类型消息

    本文地址:http://www.cnblogs.com/wuyudong/p/5900800.html,转载请注明源地址. 1.解析json数据 解析json的代码很简单 JSONObject jso ...

  6. 【转】C# 实现用艺术效果显示文本的标签控件

    C# 实现用艺术效果显示文本的标签控件 2009-09-28  来自:CS 程序员之窗 摘要:C#实现边框.浮雕.印版效果显示文字的标签控件,可以改变边框的宽度和文字边框的颜色,实现绚丽的文字显示效果 ...

  7. 将鼠标消息发送给指定的父控件_勾子

    以下类通过挂载勾子原理,实现将子控件鼠标消息发送给父控件. 调用: MousePreview mp=new MousePreview(pControl);  //pControl为父控件 //启用勾子 ...

  8. #304 – 为没有文本标题的控件定义Access 键(Defining an Access Key That Gives Focus to a Different Control)

    有些控件,并没有自己的文本标题,他们可以通过与之相邻的Label来定义自己的Access 键.通过Access 键,他们可以获得输入焦点. 下面的例子中,在"Enter Name" ...

  9. MFC_C++02_模态对话框,非模态对话框,StaticText静态文本,CEditCtrl控件,ComboBox下拉框,CListCtrl控件,CTreeCtrl 树控件,TabCtrl标签控件

    01 模态对话框创建 更改标题名: 菜单栏 --> 视图->工具箱 ,找到工具箱 导入两个按钮: 准备对话框: 插入就可以了,更改名称 双击按钮,可以进入点击事件 创建控件的类:右击-&g ...

最新文章

  1. 在SQL Server中如何转化长日期形式为短日期格式
  2. 推荐系统产品与算法概述 | 深度
  3. Azure Stack-1807 版本 配置10分钟、自动部署6小时-我的ASDK第7次实践
  4. 如何安装nginx_lua_module模块
  5. [JSConf EU 2018] 大脑控制 Javascript
  6. matlab幂次变换代码,常用的一些图像处理Matlab源代码
  7. kafka python client:PyKafka vs kafka-python
  8. Selenium2 + Python3.6实战(五):生成HTML测试报告 Invalid argument
  9. 用大前端技术实现的一款仿Boss直聘app(已开源)
  10. angular集成websocket_angular使用 websocket,少点套路,多一点真诚
  11. 基于微信小程序的AI智能识物
  12. 2017大一计算机教程,2017年计算机等考一级章节考点:WPS2000新手入门教程
  13. win7 安装英文语言包
  14. AttributeError: module 'ahocorasick' has no attribute 'Automaton'解决
  15. 萌新入坑第一课——如何写技术博客
  16. 电脑怎么设置开机密码?简单几步给你的电脑“上锁”
  17. C/C++语言入门——鸡兔同笼问题
  18. Android 高德地图中路线规划绘制界面线路
  19. 压力传感器中英文术语对照表
  20. 大众点评超详细爬虫系列2

热门文章

  1. 世界上没有哪一份工作是不受气的
  2. 电子版微积分教课书,作者是怎样精心撰写的?
  3. Unity配置文件xxx.ini
  4. C语言笔记 | 一元三次方程
  5. k8s部署springcloud架构的一些心得体会
  6. Flask asyncio 异步处理请求
  7. 《Unity Shader入门精要》笔记01 前言
  8. 计算机怎样设置开机音乐,电脑开机声音听腻了怎么办?一招教你搞定
  9. 小米最新系统android 10,小米MIUI 12再更新,基于Android 10的系统也来了,5项改变...
  10. 安卓手机玩游戏卡顿怎么解决_解决安卓手机卡顿反应慢的9个技巧