C# 使用 Windows API 操作控件: SendMessage

在C#中,程序采用了的驱动采用了事件驱动而不是原来的消息驱动,虽然.net框架提供的事件已经十分丰富,但是在以前的系统中定义了丰富的消息对系统的编程提供了方便的实现方法,因此在C#中使用消息有时候还是大大提高编程的效率的。

定义消息
在c#中消息需要定义成windows系统中的原始的6进制数字,比如
const int WM_Lbutton = 0x0; //定义了鼠标的左键点击消息
public const int USER = 0x000 // 是windows系统定义的用户消息

消息发送
消息发送是通过windows提供的API函数SendMessage来实现的它的原型定义为

[DllImport("User.dll",EntryPoint="SendMessage")]
private static extern int SendMessage(
int hWnd,   // handle to destination window
int Msg,     // message
int wParam,    // first message parameter
int lParam         // second message parameter
);


消息的接受
在C#中,任何一个窗口都有也消息的接收处理函数,就是defproc函数
你可以在form中重载该函数来处理消息

protected override void DefWndProc ( ref System.WinForms.Message m )
{switch(m.msg){case WM_Lbutton :///string与MFC中的CString的Format函数的使用方法有所不同string message = string.Format("收到消息!参数为:{0},{}",m.wParam,m.lParam);MessageBox.Show(message);///显示一个消息框break;default:base.DefWndProc(ref m);///调用基类函数处理非自定义消息。break;}
}


其实,C#中的事件也是通过封装系统消息来实现的,如果你在DefWndProc函数中不处理该
那么,他会交给系统来处理该消息,系统便会通过代理来实现鼠标单击的处理函数,因此你可以通过
defproc函数来拦截消息,比如你想拦截某个按钮的单击消息


C#中其他的消息处理方法
在C#中有的时候需要对控件的消息进行预处理,比如你用owc的spreedsheet控件来处理Excel文件,你不想让用户可以随便选中
数据进行编辑,你就可以屏蔽掉鼠标事件,这个时候就必须拦截系统预先定义好的事件(这在MFC中称为子类化),你可以通过C#提供的一个接口

IMessageFilter来实现消息的过滤

public class Form: System.Windows.Forms.Form,IMessageFilter{const int WM_MOUSEMOVE = 0x00public bool PreFilterMessage(ref Message m) {  Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode; if(m.Msg == m.Msg==WM_MOUSEMOVE) //||m.Msg == WM_LBUTTONDOWN{//MessageBox.Show("Ignoring Escape...");  return true; } return false; }
}


备注:主要描述在调用API函数SendMessage时数据类型的转换。


SendMessage是一个在user32.dll中声明的API函数,在C#中导入如下:

using System.Runtime.InteropServices;
[DllImport("user32.dll", EntryPoint="SendMessageA")]
public static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

 

本文描述其参数 lParam 的用法,主要是数据类型之间的转化。

● 一种最简单的处理方式是声明多个SendMessage函数(overload),用所需的数据类型直接替换IntPtr。例如:

//声明:
[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam,  string lParam);[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam,  ref Rectangle lParam);//调用:
string s = "hello, floodzhu";
SendMessage(this.textBox1.Handle, WM_SETTEXT, IntPtr.Zero, s);Rectangle rect = new Rectangle();
SendMessage(this.richTextBox1.Handle, EM_GETRECT, (IntPtr)0, ref rect);

● 对要求返回字符串的类型(out string)可以用 StringBuilder 代替,此时不需要 out/ref。例如:

[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, int wParam, StringBuilder 
lParam);private void button1_Click(object sender, System.EventArgs e)
{const int buffer_size = 1024;StringBuilder buffer = new StringBuilder(buffer_size);SendMessage(this.textBox1.Handle, WM_GETTEXT, buffer_size, buffer);//MessageBox.Show(buffer.ToString());
}

● 如果想用 InPtr 类型统一处理的话,可以借助于 Marshal 或者 GCHandle 的相关方法。例如:

[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);private void button2_Click(object sender, System.EventArgs e)
{Rectangle rect = new Rectangle();IntPtr buffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Rectangle)));Marshal.StructureToPtr(rect, buffer ,true);SendMessage(this.richTextBox1.Handle, EM_GETRECT, (IntPtr)0, buffer);rect = (Rectangle)Marshal.PtrToStructure(buffer, typeof(Rectangle));Marshal.FreeHGlobal(buffer);
}

或者

private void button2_Click(object sender, System.EventArgs e)
{Rectangle rect = new Rectangle();GCHandle gch = GCHandle.Alloc(rect);SendMessage(this.richTextBox1.Handle, EM_GETRECT, (IntPtr)0, (IntPtr)gch);rect = (Rectangle)Marshal.PtrToStructure((IntPtr)gch, typeof(Rectangle));gch.Free();
}
SendMessage-------PostMessage
1、首先是返回值意义的区别,我们先看一下 MSDN 里的声明:
LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
1.其中 4 个参数的意义是一样的,返回值类型不同(其实从数据上看他们一样是一个 32 位的数,只是意义不一样),LRESULT 表示的是消息被处理后的返回值,BOOL 表示的是消息是不是 Post 成功。2、PostMessage 是异步的,SendMessage 是同步的。
PostMessage 只把消息放入队列,不管消息是否被处理就返回,消息可能不被处理;而 SendMessage 等待消息被处理完了之后才返回,如果消息不被处理,发送消息的线程将一直被阻塞。3、如果在同一个线程内,SendMessage 发送消息时,由 USER32.DLL
模块调用目标窗口的消息处理程序,并将结果返回。SendMessage 在同一线程中发送消息并不入线程消息队列。PostMessage
发送消息时,消息要先放入线程的消息队列,然后通过消息循环分派到目标窗口(DispatchMessage)。如果在不同线程内,SendMessage 发送消息到目标窗口所属线程的消息队列,然后发送消息的线程在 USER32.DLL
模块内监视和等待消息处理,直到目标窗口处理完返回。SendMessage 在返回前还做了很多工作,比如,响应别的线程向它
SendMessage。Post 到别的线程时,最好用 PostThreadMessage 代替
PostMessage,PostMessage 的 hWnd 参数可以是 NULL,等效于 PostThreadMessage +
GetCurrentThreadId。Post WM_QUIT 时,应使用 PostQuitMessage 代替。4、系统只整编(marshal)系统消息(0 到 WM_USER 之间的消息),发送用户消息(WM_USER 以上)到别的进程时,需要自己做整编。用 PostMessage、SendNotifyMessage、SendMessageCallback 等异步函数发送系统消息时,参数里不可以使用指针,因为发送者并不等待消息的处理就返回,接受者还没处理指针就已经被释放了。5、在 Windows 2000/XP 里,每个消息队列最多只能存放 10,000 个 Post的消息,超过的还没被处理的将不会被处理,直接丢掉。这个值可以改得更大:[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Windows] USERPostMessageLimit,最小可以是4000。PostMessage只负责将消息放到消息队列中,不确定何时及是否处理
SendMessage要等到受到消息处理的返回码(DWord类型)后才继续
PostMessage执行后马上返回
SendMessage必须等到消息被处理后才会返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252109.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对类的理解:

在public class First 表示如果一个类的声明为public,要求该类的类名必须和文件保持一致。在编译 源文件时,让雨果源文件中定义了多个类,那么每个类会形成*.class 文件,执行是,通过Java类名,运行的的是该类…

概率论

概率论转载于:https://www.cnblogs.com/zengkefu/p/7357249.html

Hive安装中遇到过的坑

实现说明每一个用户的环境都有细微的不一致,所以这里只是个人经过这些坑的处理,但是不意味着所有处理都是这样的操作,仅作为参考。 第一个坑 数据库安装,数据库最好装在Linux上,一直出了很多错,这里有一个博…

Halcon:模版匹配

一:函数介绍 1.创建模板 create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID) Template :模板图像 NumLevels:图像金字塔级数,该值越小…

java基础英语---第二十六天

Terminate [ tə:mineit ] 结束 Instantiation [in,stnʃieiʃən] 实例化 Instance declared [diklεəd] 公然的 Access [ əkses ] 进入,接近,入口,通道 Accessible [əksesəbl] 可进入的 invoke [invəuk] 调用 board [bɔ:d] 木板,甲板 MainBoard card [kɑ:d] …

ASP.NET Core部署到Linux服务器(CentOS7 x64)

前言 本文主要讲解如何一步步将ASP.NET Core网站发布到Linux服务器,文中会讲解具体步骤及需要避免的各种问题。 目录 一、环境介绍 二、创建及发布ASP.NET Core网站项目 三、服务器软件安装(.NET Core SDK) 四、在服务器上部署ASP.NET Core网…

redux进一步优化

1. 将原来的 mapStateToDispatch 中的函数提取出来,放在组件中, 如原来的: function mapStateToProps(state, ownProps) {return {hasMore:state.getIn([tabs,hasMore]),} } function mapDispatchToProps(dispatch) {return {addTabList:(i…

C# : 调用C++动态库(dll)

在实际软件开发过程中,由于公司使用了多种语言开发,在C#中可能需要实现某个功能,而该功能可能用其他语言已经实现了,那么我们可以调用其他语言写好的模块吗?还有就是,由于C#开发好的项目,我们可…

Python3.5以上版本lxml导入etree报错Unresolved reference

Web抓取Web站点使用HTML描述,这意味着每个web页面是一个结构化的文档。有时从中 获取数据同时保持它的结构是有用的。web站点不总是以容易处理的格式, 如 csv 或者 json 提供它们的数据。 这正是web抓取出场的时机。Web抓取是使用计算机程序将web页面数据…

linux设置history历史记录

#说明export HISTSIZE1000 #设置历史记录显示1000行export HISTTIMEFORMAT%F %T #设置历史记录格式 999 2017-08-15 10:58:32 #修改vim /etc/profilesed -i "s/\(HISTSIZE\).*/\11000/" /etc/profilesed -i "/HISTSIZE/aexport HISTTIMEFORMAT%F %T " /et…

STL-容器库101--array【C11】

1. 原型 C11提供 template < class T, size_t N > class array;T&#xff1a; 元素类型&#xff0c;以 array::value_type 作为别名使用&#xff1b;N&#xff1a; array中元素大小&#xff1b; 固定size的序列容器&#xff1b;初始化时&#xff0c; array对象不保存任何…

C#:向C++封送结构体数组

在使用第三方的非托管API时&#xff0c;我们经常会遇到参数为指针或指针的指针这种情况&#xff0c; 一般我们会用IntPtr指向我们需要传递的参数地址&#xff1b; 但是当遇到这种一个导出函数时,我们如何正确的使用IntPtr呢&#xff0c; extern "C" __declspec(dll…

其它综合-CentOS7 忘记root密码

CentOS7 忘记root密码 长时间不用的 CentOS 机器再次开机的时候忽然忘记了密码&#xff0c;总不能就重装一台吧&#xff0c;还有好多服务在机器上&#xff0c;于是决定重置root的密码。   如果是已经开启的机器&#xff0c;需要进行关闭&#xff0c;重新启动。在启动选择内核…

left join on and 与 left join on where的区别

数据库在通过连接两张或多张表来返回记录时&#xff0c;都会生成一张中间的临时表&#xff0c;然后再将这张临时表返回给用户。 在使用left jion时&#xff0c;on和where条件的区别如下&#xff1a; 1、 on条件是在生成临时表时使用的条件&#xff0c;它不管on中的条件是否为真…

spring boot高性能实现二维码扫码登录(中)——Redis版

前言 本打算用CountDownLatch来实现&#xff0c;但有个问题我没有考虑&#xff0c;就是当用户APP没有扫二维码的时候&#xff0c;线程会阻塞5分钟&#xff0c;这反而造成性能的下降。好吧&#xff0c;现在回归传统方式&#xff1a;前端ajax每隔1秒或2秒发一次请求&#xff0c;去…

C# :socket 通讯基础使用实例

们在讲解Socket编程前&#xff0c;先看几个和Socket编程紧密相关的概念&#xff1a; TCP/IP层次模型当然这里我们只讨论重要的四层 01&#xff0c;应用层(Application)&#xff1a;应用层是个很广泛的概念&#xff0c;有一些基本相同的系统级TCP/IP应用以及应用协议&#xff0…

IBM发表论文:可能已找到处理量子计算退相干的方法

在《自然》杂志最近发表的一篇论文中&#xff0c;IBM和其他机构的研究人员设计了两种量子算法&#xff0c;利用变分量子电路和量子核估计器来训练一种支持向量机分类器。这两种算法背后的关键思想是使用量子状态空间作为特征空间表示&#xff0c;有效地构建映射&#xff0c;从原…

PHP + NGINX 控制视频文件播放,并防止文件下载

最简单的方法是使用NGINX的 internal 功能 server { listen 80; server_name www.xxx.com;  location / { index index.php index.html index.htm; root /xxx; if (!-e $request_filename) { rewrite ^/index.php(.*)$ /index.php?s$…

可视化调试工具

rosrun rqt_console rqt_console # 查看日志消息&#xff0c;可filter、highlight指定级别。 rosrun rqt_logger_level rqt_logger_level # 可设在日志记录器的严重级别 rosrun rqt_topic rqt_topic # 显示topic调试信息 rosrun rqt_publisher rqt_publisher # 在界面中管理ro…

C#:委托基础与事件

通过以下思维导图&#xff0c;学习委托的基本概念&#xff0c;后面着重讲解委托的运用&#xff0c;希望通过最简单的方式收获更多的知识。 1.委托的各种写法 1、委托 委托名new 委托&#xff08;会调用的方法名); 委托名&#xff08;参数&#xff09;; 2、委托 委托名 会调用…