zoukankan      html  css  js  c++  java
  • 【Win32 API】利用SendMessage实现winform与wpf之间的消息传递

    引言

       有一次心血来潮,突然想研究一下进程间的通信,能够实现消息传递的方法有几种,其中win32api中的sendmessage就是当中的一种比较简单的方法。于是参考了网上各种资料,做了一个小demo。

    发送方Winform

       1.新建一个Winform项目,添加控件,如下

    2.界面做好,接着来编写代码,首先利用DllImport来声明SendMessage函数原型,如下:

    [DllImport("User32.dll")]
            private static extern int SendMessage(IntPtr hWnd,int Msg, int wParam, IntPtr lParam );
    View Code

    3.其中,lParam参数说明如下

     lParam指向一个COPYDATASTRUCT的结构:  
     typedef  struct  tagCOPYDATASTRUCT
     {  
                 DWORD  dwData;  //用户定义数据  
                 DWORD  cbData;  //数据大小  
                PVOID  lpData;  //指向数据的指针  
     } COPYDATASTRUCT;  

    4.所以为了方便起见,还需要定义个一个结构,如下

     public struct COPYDATASTRUCT
            {
                public IntPtr dwData;
                public int cbData;
                [MarshalAs(UnmanagedType.LPStr)]
                public string lpData;
            }
    View Code

    5.相应地,sendmessage函数更改为如下:

    [DllImport("User32.dll")]
            private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam );
    View Code

    6.至此,sendmessage函数定义完成,但是还不够,我们还需要能找到接收消息的窗体的函数,所以还要声明两个函数:

            [DllImport("User32.dll", EntryPoint = "FindWindow")]
            private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("user32.dll", EntryPoint = "FindWindowEx“)]
            private static extern IntPtr FindWindowEx(IntPtr hwndParent, uint hwndChildAfter, string lpszClass, string lpszWindow);
    View Code

    7.接下来,我们可以开始写发送消息具体实现。
       发送到form的textbox按钮的方法实现如下:

                IntPtr WINDOW_HANDLER = FindWindow(null, "Win32窗体");
    
                if (WINDOW_HANDLER != IntPtr.Zero)
                {
                   
                    IntPtr hwndThree = FindWindowEx(WINDOW_HANDLER, 0, null, ""); 
                    hwndThree =new IntPtr(GetWindow(hwndThree.ToInt32(), 2));
                    hwndThree = new IntPtr(GetWindow(hwndThree.ToInt32(), 2));   //获取按钮的句柄  找3次才找到目标textbox
    
                    SendMessage(hwndThree, WM_SETTEXT, 0, this.sendtext.Text);
                }
    View Code

      发送到Winform按钮的方法实现如下:

         IntPtr WINDOW_HANDLER = FindWindow(null, "Win32窗体");
                if (WINDOW_HANDLER != IntPtr.Zero)
                {
                    string text = this.sendtext.Text;
                    byte[] sarr = System.Text.Encoding.Default.GetBytes(text);
                    int len = sarr.Length;
                    COPYDATASTRUCT cds;
                    cds.dwData = (IntPtr)100;
                    cds.lpData = text;
                    cds.cbData = len + 1;
                    SendMessage(WINDOW_HANDLER, WM_COPYDATA, 0, ref cds);
                }
    View Code

      发送到WPF按钮的方法实现如下:

    IntPtr WINDOW_HANDLER = FindWindow(null, "WPF窗体");
                if (WINDOW_HANDLER != IntPtr.Zero)
                {
                    string text = this.sendtext.Text;
                    byte[] sarr = System.Text.Encoding.Default.GetBytes(text);
                    int len = sarr.Length;
                    COPYDATASTRUCT cds;
                    cds.dwData = (IntPtr)100;
                    cds.lpData = text;
                    cds.cbData = len + 1;
                    SendMessage(WINDOW_HANDLER, WM_COPYDATA, 0, ref cds);
                }
    View Code

    8.至此,发送端的编码完成,其中第一个按钮的功能是将消息直接发送到winform接收方的textbox上,第二个按钮是将消息发送到winform接收方的窗体上,再由窗体的方法处理,第三个按钮是将消息发送到wpf接收方的窗体上,再由wpf的方法处理。为什么没有直接发送到wpf的textbox的方法呢,那是因为wpf里面的控件是没有句柄的,只有窗体才有句柄,然后发送消息需要接收方的句柄,所以无法实现。

     接收方winform

      1.新建winform项目,编写界面如下:

      2.编写后台代码,定义结构COPYDATASTRUCT和重写winform的消息处理方法WndProc,代码如下:

    public const int WM_COPYDATA = 0x004A;
    
     public struct COPYDATASTRUCT
            {
                public IntPtr dwData;
                public int cbData;
                [MarshalAs(UnmanagedType.LPStr)]
                public string lpData;
            }
    
     protected override void WndProc(ref System.Windows.Forms.Message m)
            {
                switch (m.Msg)
                {
                    case WM_COPYDATA:
                        COPYDATASTRUCT MyKeyboardHookStruct = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
                        this.textBox2.Text = MyKeyboardHookStruct.lpData;
                        break;
                    default:
                        base.WndProc(ref m);   // 调用基类函数处理其他消息。   
                        break;
                }
            }  
    View Code

    3.至此,winform接收端编码完成,我们只需在WndProc处理一下消息类型为WM_COPYDATA的消息即可。

    接收方wpf

       1.新建wpf项目,界面如下

    2.编写后台代码,wpf没有消息处理方法WndProc,所以处理上复杂些。主要利用HwndSource实现接收消息,具体代码如下:

     public MainWindow()
            {
                InitializeComponent();
                
                this.Loaded += Window_Loaded;
            }
            
    
    
    
            #region 定义常量消息值
            public const int WM_GETTEXT = 0x0D;
            public const int WM_SETTEXT = 0x0C;
            public const int WM_SIZEING = 0x0214;
            public const int WM_COPYDATA = 0x004A;
            public const int WM_LBUTTONDBLCLK = 0x0203;
            #endregion
    
            #region 定义结构体
           public struct COPYDATASTRUCT
            {
                public IntPtr dwData;
                public int cbData;
                [MarshalAs(UnmanagedType.LPStr)]
                public string lpData;
            }
            #endregion
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                HwndSource hWndSource;
                WindowInteropHelper wih = new WindowInteropHelper(this);
                hWndSource = HwndSource.FromHwnd(wih.Handle);
                //添加处理程序 
                hWndSource.AddHook(MainWindowProc);
            }
            private IntPtr MainWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
            {
                switch (msg)
                {
                  
                    case WM_COPYDATA:
                        {
    
                            COPYDATASTRUCT mystr = new COPYDATASTRUCT();
                            Type mytype = mystr.GetType();
    
                            COPYDATASTRUCT MyKeyboardHookStruct = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
                             this.textbox.Text = MyKeyboardHookStruct.lpData;
                            break;
    
                        }
                         default:
                        {
                                 break;
                        }
    
    
                }
                return IntPtr.Zero;
            }
    View Code

    3.wpf接收端完成。
    最终界面效果

    小结

         本文介绍了如何用sendmessage函数在窗体间发送消息,sendmessage函数是win32api的一种,然而win32api又是一个好庞大的话题了,我现在还只是入门未遂,渐行渐学罢了.另外,消息的传递方法不只一种,例如我们还可以用wcf进行通信,有时间再研究.最后,如果您有更好的建议,请不吝指教,感激不尽!

  • 相关阅读:
    Zepto swipe 无效(坑)
    Zepto.js-Ajax 请求
    Zepto.js-事件处理
    excel 大文件解析原理实现
    springboot 集成J2Cache
    springboot 单元测试 指定启动类
    springboot 解决 数字长度过长导致JS精度丢失问题
    JS 基本操作
    VUE 动态菜单管理
    VUE router-view key 属性解释
  • 原文地址:https://www.cnblogs.com/caizl/p/4343199.html
Copyright © 2011-2022 走看看