当前位置:首页 > C#编程 > C#/.net框架 > 正文内容

C#中使用RegisterWindowMessage进行进程之间进行通讯

Jorge2年前 (2022-05-08)C#/.net框架733

注:

大家都知道在window里,进程之间通讯可以用消息通讯。

但是有个较冷门的知识就是RegisterWindowMessage。一般的sendmessage和postmessage是需要在窗体程序间进行通讯,你得知道对方窗口的句柄。

这个句柄每次启动程序时是系统分配的,每次不一样。

有了这个RegisterWindowMessage,两个进程可以共同持有一个相同的“句柄”,然后两者的顶层窗体间可以持这个“句柄”进行通讯。你不需要知道对方的窗体句柄是什么!


下面是引用自网络的文章,作者用C++讲述。


C#
进程间通信的方法有很多,比如使用注册消息,内存映射,WM_COPYDATA等,下面先讲使用注册消息实现的方法。

使用注册消息比较简单,核心是消息的接收端和消息的发送端(接收端和发送端在两个不同的进程)必须注册相同的消息,这样发送消息才能识别。
下面看看具体实现:

一,发送消息进程1, 在发送消息程序A注册消息:const UINT WM_UPDATE_ALARMFILTER = ::RegisterWindowMessage(_T("UpdateAlarmFilter"));2,在程序需要发送消息时调用:    ::PostMessage(HWND_BROADCAST, WM_UPDATE_ALARMFILTER, 0, 0);参数HWND_BROADCAST表示将该消息发送到所有top-level的窗口,including disabled or invisible unowned windows, overlapped windows, and pop-up windows. The message is not posted to child windows.如果不想发给所有顶层窗口,只想发给指定窗口,就不使用HWND_BROADCAST参数,获得要发送窗口的句柄即可:
    CWnd *pWnd = CWnd::FindWindow(NULL,_T("NMS Server")); // 查找A进程

    if(pWnd != NULL)
    {
        pWnd->PostMessage(WM_UPDATE_ALARMFILTER, 0, 0);
    }二,接收消息进程1,在接收消息程序B,同样注册消息:const UINT WM_UPDATE_ALARMFILTER = ::RegisterWindowMessage(_T("UpdateAlarmFilter"));2,定义消息映射:ON_REGISTERED_MESSAGE(WM_UPDATE_ALARMFILTER, OnUpdateAlarmFilter) 3, 在头文件声明:
afx_msg LRESULT OnUpdateAlarmFilter(WPARAM wParam, LPARAM lParam);4,在cpp文件定义函数:
LRESULT CMainFrame::OnUpdateAlarmFilter(WPARAM wParam, LPARAM lParam){
    // 消息处理
    return 1;}注意:要在消息的发送进程和接收进程注册同样的消息ID。
在接收端,如果不用消息宏定义,可以重载PreTranslateMessage,截取消息,然后处理:
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg){
 if(pMsg->message == WM_UPDATE_ALARMFILTER)
 {
    // 消息处理
 }
 return CDialog::PreTranslateMessage(pMsg);}


下面是勇哥编写的C#版演示程序。


首先是接收端:

image.png

C#
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Runtime.InteropServices;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace WindowsFormsApplication1{
    public partial class Form1 : Form    {
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern uint RegisterWindowMessage(string lpString);

        uint h = 0;
        public IntPtr hwndTest;

        public Form1()
        {
            InitializeComponent();
            h=RegisterWindowMessage("lxy123456");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            hwndTest = this.Handle;
        }

        protected override void DefWndProc(ref Message msg)
        {
            if (msg.Msg == h)
            {
                MessageBox.Show("kkkkk");
            }
            base.DefWndProc(ref msg);
        }

        public override bool PreProcessMessage(ref Message msg)
        {
            if(msg.Msg== h)
            {
                MessageBox.Show("kkkkk");
            }
            return base.PreProcessMessage(ref msg);
        }

      
    }}


下面是发送端:

image.png


发送端注释了一部分代码,是想试试用sendmessage,postmessage发送不同的数据类型。

C#
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Runtime.InteropServices;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace WindowsFormsApplication2{
    public partial class Form1 : Form    {
     

        public class Win32API
        {

            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern uint RegisterWindowMessage(string lpString);


            [DllImport("User32.dll", EntryPoint = "FindWindow")]
            public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

            [DllImport("User32.dll", EntryPoint = "FindWindowEx")]
            public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);

            /// <summary>
            /// 自定义的结构
            /// </summary>
            public struct My_lParam            {
                public int i;
                public string s;
            }
            /// <summary>
            /// 使用COPYDATASTRUCT来传递字符串
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            public struct COPYDATASTRUCT            {
                public IntPtr dwData;
                public int cbData;
                [MarshalAs(UnmanagedType.LPStr)]
                public string lpData;
            }
            //消息发送API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // 信息发往的窗口的句柄
                int Msg,            // 消息ID
                int wParam,         // 参数1
                int lParam          //参数2
            );


            //消息发送API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // 信息发往的窗口的句柄
                int Msg,            // 消息ID
                int wParam,         // 参数1
                ref My_lParam lParam //参数2
            );

            //消息发送API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // 信息发往的窗口的句柄
                int Msg,            // 消息ID
                int wParam,         // 参数1
                ref COPYDATASTRUCT lParam  //参数2
            );

            //消息发送API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // 信息发往的窗口的句柄
                int Msg,            // 消息ID
                int wParam,         // 参数1
                int lParam            // 参数2
            );



            //消息发送API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // 信息发往的窗口的句柄
                int Msg,            // 消息ID
                int wParam,         // 参数1
                ref My_lParam lParam //参数2
            );

            //异步消息发送API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // 信息发往的窗口的句柄
                int Msg,            // 消息ID
                int wParam,         // 参数1
                ref COPYDATASTRUCT lParam  // 参数2
            );



        }
    

       uint handle = 0;
        public IntPtr hwndTest=(IntPtr)0xffff;

        public Form1()
        {
            InitializeComponent();
            handle =Win32API.RegisterWindowMessage("lxy123456");
            //hwndTest=Win32API.FindWindow(null, "lxy1");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string strTest = "25425";
            Win32API.COPYDATASTRUCT cds;
            cds.dwData = (IntPtr)100;
            cds.lpData = strTest;
            byte[] sarr = System.Text.Encoding.UTF8.GetBytes(strTest);
            int len = sarr.Length;
            cds.cbData = len + 1;

            Win32API.My_lParam lp = new Win32API.My_lParam();
            lp.i = 3;
            lp.s = "test";

            if (hwndTest != (IntPtr)0)
            {
                //if (DateTime.Now.Second % 2 == 0)
                //{
                //    Win32API.SendMessage(hwndTest, /*0x60*/(int)handle, 1, 3);//传递2个整型参数成功
                //}
                //if (DateTime.Now.Second % 3 == 0)
                //{
                //    Win32API.SendMessage(hwndTest, /*0x61 */ (int)handle, 5, ref lp);//传递整型参数和结构类型成功,这个方法加以改变后可以传递对象
                //}
                //if (DateTime.Now.Second % 5 == 0)
                //{
                //    Win32API.SendMessage(hwndTest, /*0x62 */ (int)handle, 5, ref cds);//传递整型参数和不定长的字符串成功
                //}
                //if (DateTime.Now.Second % 7 == 0)
                //{
                //    Win32API.PostMessage(hwndTest, /*0x63 */ (int)handle, 5, 6);//传递2个整型参数成功
                //}
                //if (DateTime.Now.Second % 9 == 0)
                //{
                //    Win32API.PostMessage(hwndTest, /*0x64 */ (int)handle, 3, ref lp);//传递整型参数成功,但是传递参数lp失败,3可以传递成功。
                //}
                //if (DateTime.Now.Second % 11 == 0)
                //{
                //    Win32API.PostMessage(hwndTest, /*0x65 */ (int)handle, 3, ref cds);//传递整型参数成功,传递参数cds失败,3可以传递成功。
                //}
                Win32API.PostMessage(hwndTest, /*0x65 */ (int)handle, 3,ref lp);//传递整型参数成功,传递参数cds失败,3可以传递成功。
            }
        }





    
    }}


不过,由于postmessage在C#中没办法传送对象和字符串,所以也是一点小遗憾。(C++中是有办法的)

另外,HWND_BROADCAST枚举值是0xffff,万能的度娘没办法告诉我这个。

如果不使用RegisterWindowMessage的话,你得在sendmessage的时候由某个ini获取对方程序启动后写入的自己的窗口句柄,还是比较麻烦的。

当然,你也可以findwindow自己来找,还是比较麻烦。



--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文为博主原创文章,转载请附上博文链接!


扫描二维码推送至手机访问。

版权声明:本文由7点博客发布,如需转载请注明出处。

本文链接:http://6dot.cn/?id=43

标签: .NET.NET框架
分享给朋友:

“C#中使用RegisterWindowMessage进行进程之间进行通讯” 的相关文章

C#字符串与享元(Flyweight)模式

C#字符串与享元(Flyweight)模式

注:关注这个话题是因为看到C#的关键字 lock时,其传入引用对象。因为string也是引用对象,所以能否做为lock的参数?对于这个问题,要搞明白C#的字符串的一个特点,它使用类似于享元模式的机制。因此在lock中锁字符串是相当不安全的。下面贴子是对C#字符串与享元模式的深入讨论。写这个文章,主要...

C#:多进程开发,控制进程数量

C#:多进程开发,控制进程数量

正在c#程序优化时,如果多线程效果不佳的情况下,也会使用多进程的方案,如下:C#System.Threading.Tasks.Task task=System.Threading.Tasks.Task.Factory.StartNew(     &...

关于C#项目引用的一点经验

关于C#项目引用的一点经验

关于项目引用,有几种:(一)这种是引用系统的程序集(二)下面这种是引用你自己的项目“解决方案”(三)最后一种是浏览本机上的项目的dll。对于工程中有几十个项目的软件来说,虽然使用(二)是很方便。但是会编译速度奇慢,而且随着项目越多越慢。貌似他run之前都会把所有项目都试图更新一下。勇哥宿舍的电脑,实...

c#——表达式树在LINQ动态查询

c#——表达式树在LINQ动态查询

一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件简单方式这样操作就可以了C#public IQueryable<FileImport> DynamicChainedSyntax (IQueryable<FileImport&g...

C# 不要阻塞异步代码,即异步代码死锁的最佳解决方案

C# 不要阻塞异步代码,即异步代码死锁的最佳解决方案

这是一个在论坛和 Stack Overflow 上反复提出的问题。我认为这是异步新手在学习了基础知识后最常问的问题。用户界面示例我们编写了下面的例子。单击按钮将启动 REST 调用并在文本框中显示结果(此示例适用于 Windows 窗体,但相同的原则适用于任何UI 应用程序)。C#using&nbs...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。