c#如何处理自定义消息

简介:

 

 

C#自定义消息通信往往采用事件驱动的方式实现,但有时候我们不得不采用操作系统的消息通信机制,例如在和底层语言开发的DLL交互时,是比较方便的。下面列举了一些实现方式,以供参考。有关C#中的消息机制,请参考文章C# 消息处理机制及自定义过滤方式

 

一、通过SendMessage或postmessage函数发送

1、  定义消息

在C++中引用底层的函数很简单,自定义消息如下

#define WM_TEST WM_USER + 101

而在c#中消息需要定义成windows系统中的原始的16进制数字,比如自定义消息

public const int USER = 0x0400;

public const int WM_TEST =USER+101;

2、  发送消息

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

复制代码
[DllImport("User32.dll",EntryPoint="SendMessage")]
private static extern int SendMessage(
  IntPtr hWnd,      // 窗体句柄
  uint Msg,         // 消息的标识符
  uint wParam,      // 具体取决于消息
  uint lParam       // 具体取决于消息
  );
[DllImport("User32.dll",EntryPoint="PostMessage")]
private static extern int SendMessage(
  IntPtr hWnd,      // 接收消息的那个窗口的句柄。如设为HWND_BROADCAST,表示投递给系统中的所有顶级窗口。如设为零,表示投递一条线程消息(可参考PostThreadMessage)
  uint Msg,         // 消息的标识符
  uint wParam,      // 具体取决于消息
  uint lParam       // 具体取决于消息
);
复制代码

至于两个函数的区别这里就不累述了,有兴趣的朋友可以自己查阅资料。

 

3、  消息接收

消息发出之后,在Form中如何接收呢?我们可以重载DefWinproc函数来接收消息。

复制代码
protected override void DefWndProc ( ref System.Windows.Forms.Message m )
{
            switch(m.Msg)
            {
                case Message.WM_TEST:   //处理消息
                break;
                default:
                base.DefWndProc(ref m);   //调用基类函数处理非自定义消息。
         break;
            }
}
复制代码

二、使用PostThreadMessage函数向线程发送消息

1、映射消息结构体原型和自定义消息

1
2
3
4
5
6
7
8
9
10
public  struct  tagMSG
{
             public  int  hwnd;
             public  uint  message;
             public  int  wParam;
             public  long  lParam;
             public  uint  time;
             public  int  pt;
         }
public  const  int  WM_CX_NULL = 0x400 + 100;

2、发送消息

复制代码
[DllImport("user32.dll")]
private static extern int PostThreadMessage(
                  int threadId,   //线程标识
                   uint msg,      //消息标识符
                  int wParam,   //具体由消息决定
                   int lParam);  //具体由消息决定
复制代码

此函数获取当前线程一个唯一的线程标识符,这点需要特别注意:Win32 API无法识别管理线程,你必须发送消息到Windows的线程ID上,而不是管理线程的ID上。

[DllImport("kernel32.dll")]

private static extern int GetCurrentThreadId();

因此发送消息过程如下:

private int _NewThreadId =GetCurrentThreadId();

PostThreadMessage(_NewThreadId, WM_CX_NULL, 1, 1);

 

3、接收消息

该函数从调用线程的消息队列里取得一个消息并将其放于指定的结构。此函数可取得与指定窗口联系的消息和由PostThreadMesssge寄送的线程消息。此函数接收一定范围的消息值。GetMessage不接收属于其他线程或应用程序的消息。

复制代码
[DllImport("user32.dll")]
private static extern int GetMessage(
ref tagMSG lpMsg, //指向MSG结构的指针,该结构从线程的消息队列里接收消息信息;
int hwnd,       //取得其消息的窗口的句柄。这是一个有特殊含义的值(NULL)。GetMessage为任何属于调用线程的窗口检索消息;                                                 int wMsgFilterMin,     //指定被检索的最小消息值的整数
int wMsgFilterMax);    //指定被检索的最大消息值的整数
复制代码

接收实现如下:

复制代码
public void ThreadExectue()
{
           _NewThreadId= GetCurrentThreadId();  //发送线程和接收线程一定要是同一个线程,否则接收不到消息
            while (GetMessage(ref msg, 0, 0, 0) > 0)
            {
                if (msg.message == WM_CX_NULL)
                {
                    MessageBox.Show("消息收到!");
                }
            }
}
复制代码

 

 

 

 三、拦截系统消息

使用 Application.AddMessageFilter。

 

1、实现消息过滤器接口

 

复制代码
internal class MyMessager : IMessageFilter
{
            //截取消息,进行处理
            public bool PreFilterMessage(ref System.Windows.Forms.Message m)
            {
                switch (m.Msg)
                {
                     case CUSTOM_MESSAGE:      //拦截自定义消息 
                        MessageBox.Show("消息收到!");
                        return true;                      
                     default:
                        return false;           //返回false则消息未被裁取,系统会处理
                }
            }
}
复制代码

 

2、安装消息过滤器

 private void Form1_Load(object sender, EventArgs e)
  {
       Application.AddMessageFilter(new MyMessager());
  }

 

C#简单实现自定义消息的发送和接收示例:

复制代码
//=================================发送窗口代码=============================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

//手动加入的命名空间
using System.Runtime.InteropServices;
namespace SendCustomMessage
{
    public partial class SendForm. Form
    {
        public SendForm(IntPtr Handle)
        {
            SendToHandle = Handle;
            InitializeComponent();
        }
        private IntPtr SendToHandle;//这个变量用于保存要发送窗口的句柄
        //自定义的消息
        public const int USER = 0x500;
        public const int MYMESSAGE=USER + 1;
        //消息发送API
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(
        IntPtr hWnd,        // 信息发住的窗口的句柄
        int Msg,            // 消息ID
        int wParam,         // 参数1
        ref SENDDATASTRUCT lParam // 参数2   [MarshalAs(UnmanagedType.LPTStr)]StringBuilder lParam
        );
        //发关按钮
        private void Send_Click(object sender, EventArgs e)
        {
            string myText = textBox1.Text;
            byte[] myInfo = System.Text.Encoding.Default.GetBytes(myText);
            int len = myInfo.Length;
            SENDDATASTRUCT myData;
            myData.dwData = (IntPtr)100;
            myData.lpData = myText;
            myData.DataLength = len + 1;
            SendMessage(SendToHandle, MYMESSAGE, 100, ref myData);//发送自定义消息给句柄为SendToHandle 的窗口,
                                                                //本例为创建本窗口的窗口句,创建时,传递给本窗口的构造函数
        }
    }
    //要发信息数据结构,作为SendMessage函数的LParam参数
    public struct SENDDATASTRUCT
    {
        public IntPtr dwData;       //附加一些个人自定义标志信息,自己喜欢
        public int DataLength;      //信息的长度
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpData;       //要发送的信息
    }
}
//=============================接收窗口代码====================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
/*
 制作人:林龙江
 制作时间:2007年5月1日
 只供参考,有错误之处请指出 !
 */
//手动加入的命名空间
using System.Runtime.InteropServices;
namespace SendCustomMessage
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            sendForm. = new SendForm(this.Handle);
            sendForm.Show();
        }
        SendCustomMessage.SendForm. sendForm;
        //自定义消息
        public const int USER = 0x500;
        public const int MYMESSAGE = USER + 1;
        ///重写窗体的消息处理函数DefWndProc,从中加入自己定义消息 MYMESSAGE 的检测的处理入口
        protected override void DefWndProc(ref Message m)
        {
            switch (m.Msg)
            {
                //接收自定义消息MYMESSAGE,并显示其参数
                case MYMESSAGE:
                    SendCustomMessage.SENDDATASTRUCT myData = new SendCustomMessage.SENDDATASTRUCT();//这是创建自定义信息的结构
                    Type mytype = myData.GetType();
                    myData = (SendCustomMessage.SENDDATASTRUCT)m.GetLParam(mytype);//这里获取的就是作为LParam参数发送来的信息的结构
                    textBox1.Text = myData.lpData; //显示收到的自定义信息
                    break;
                default:
                    base.DefWndProc(ref m);
                    break;
            }
        }
    }
}
复制代码

 

 

 

参考文章

c#如何处理自定义消息

 

没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。





    本文转自wenglabs博客园博客,原文链接:http://www.cnblogs.com/arxive/p/7683837.html ,如需转载请自行联系原作者



相关文章
|
关系型数据库 MySQL C#
C# winform 一个窗体需要调用自定义用户控件的控件名称
给用户控件ucQRCode增加属性: //二维码图片 private PictureBox _pictureBoxFSHLQrCode; public PictureBox PictureBoxFSHLQrCode {   get { return _pictureBoxFSHLQrCode; }   set { this.pictureBoxFSHLQrCode = value; } } 在Form1窗体直接调用即可: ucQRCode uQRCode=new ucQRCode(); ucQRCode.PictureBoxFSHLQrCode.属性= 要复制或传给用户控件上的控件的值
72 0
|
6月前
|
C# C++
C# 自定义时间进度条
本文作者通过参考leslie_xin的一篇文章,成功创建了一个自定义的WinForms控件——时间进度条,该控件带有时间刻度和多种可定制的属性,如颜色、时间间隔等。作者在控件中加入了开始和结束时间,以及自适应的时间刻度间隔。控件能根据设置显示时间标签,并提供了事件处理,如值改变时的触发。代码中包含了计算时间刻度、绘制刻度线和时间标签的逻辑。作者强调了避免循环调用事件、使用OnXXX()形式的事件处理函数以及注意自定义控件中的属性和事件设计。
144 7
|
4月前
|
开发框架 .NET 编译器
总结一下 C# 如何自定义特性 Attribute 并进行应用
总结一下 C# 如何自定义特性 Attribute 并进行应用
114 1
|
编译器 C#
c# 自定义扩展方法
c# 自定义扩展方法
|
7月前
|
移动开发 JavaScript 安全
C# 实现微信自定义分享
C# 实现微信自定义分享
|
7月前
|
C#
C#学习相关系列之自定义遍历器
C#学习相关系列之自定义遍历器
C#或Winform中的消息通知之自定义优雅漂亮的通知效果
Custom Notification自定义通知提示,一款非常优雅漂亮的自定义通知效果,主要介绍其实现思路、调整和优化...
1268 0
C#或Winform中的消息通知之自定义优雅漂亮的通知效果
|
编译器 C#
C#中导入其它自定义的命名空间
c#中怎么导入其它自定义的命名空间首先要确保已经导入了想要导入的自定义的命名空间。如上图这时编译器应该会报错,此时就需要手动去添加引用了,cs文件默认没有添加引用,只是加载了想要导入的命名空间,但是没有添加引用,所以需要自己要手动添加引用。切记!然后会有一个对话框选择你想引用的命名空间,点击确定即可。注意:一般而言,C#中如果没有改变那么一般项目的类名都默认是Program,在引用时需要注...
114 1
C#中导入其它自定义的命名空间
|
C# 图形学
C#绘制自定义小人
C#绘制自定义小人
|
存储 设计模式 缓存
C# 实现 key-value 结构自定义缓存 CustomCache
C# 实现 key-value 结构自定义缓存 CustomCache
188 1
C# 实现 key-value 结构自定义缓存 CustomCache