【Win32 API】利用SendMessage實現winform與wpf之間的消息傳遞

引言api

   有一次心血來潮,忽然想研究一下進程間的通訊,可以實現消息傳遞的方法有幾種,其中win32api中的sendmessage就是當中的一種比較簡單的方法。因而參考了網上各類資料,作了一個小demo。ide

發送方Winform函數

   1.新建一個Winform項目,添加控件,以下ui

2.界面作好,接着來編寫代碼,首先利用DllImport來聲明SendMessage函數原型,以下:this

[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;  spa

4.因此爲了方便起見,還須要定義個一個結構,以下3d

 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函數定義完成,可是還不夠,咱們還須要能找到接收消息的窗體的函數,因此還要聲明兩個函數:code

        [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進行通訊,有時間再研究.最後,若是您有更好的建議,請不吝指教,感激涕零!

相關文章
相關標籤/搜索