WM_COPYDATA實現的不一樣進程間通訊

進程間通訊,經過SendMessage向另外一進程發送WM_COPYDATA消息,實現不一樣進程間的消息通訊。
需求:已寫好一個工具軟件,想在不更改當前的軟件開發的前提下,實現爲後面新開發的軟件提供數據推送任務。原先想到使用,WCF以實現通訊級別的調用,但對於後續新開發的軟件來講,所需實現的東西太多(至關於須要實現一個既定接口的服務端)。因此選擇使用SendMessage,發送一個WM_COPYDATA以實現對新軟件的通知任務。其中主要是須要對傳輸一個對象級的處理,須要進行序列化及反序列貨處理,這是比較重要的一點。其餘方面都比較簡單,只是單獨發一條WM_COPYDATA消息。

1、找到新軟件需被通知的窗口(通常是以配置的形式實現)

  而在原有軟件(即主消息推送方)經過既定的擴展軟件名稱經過:FindWindow函數進行查找對象句柄,以待後續發送消息。

2、發送消息

  須要建立WM_COPYDATA消息所需的傳參結構,默認狀況下能夠傳遞字符串,因此如只單獨傳輸字符串,那就沒什麼問題的,直接簡單調用便可。但在此,須要傳輸的爲對象,因此,須要將對象先進行一系列處理,以便格式化爲字符串進行傳輸。在接收方再以逆運算得出傳輸過來的對象。

3、將對象序列化爲字符串及反序列化的操做,經過一個幫助類實現

Demo代碼:

傳輸類:
 1 using System;
 2 using System.Collections.Generic;
 3 using System.IO;
 4 using System.Linq;
 5 using System.Runtime.InteropServices;
 6 using System.Runtime.Serialization.Formatters.Binary;
 7 using System.Text;
 8 using System.Threading.Tasks;
 9 namespace Dralee.AppTransferMsg.Common
10 {
11     [Serializable]
12     public class Msg
13     {
14         public string SentBy { get; set; }
15         public string RcvBy { get; set; }
16         public string Message { get; set; }
17         public DateTime SentOn { get; set; }
18         public Msg()
19         {
20         }
21         public Msg(string sentBy, string rcvBy, string msg, DateTime sentOn)
22         {
23             SentBy = sentBy;
24             RcvBy = rcvBy;
25             Message = msg;
26             SentOn = sentOn;
27         }
28         public static byte[] Serialize(Msg msg)
29         {
30             MemoryStream ms = new MemoryStream();
31             BinaryFormatter bf = new BinaryFormatter();
32             bf.Serialize(ms, msg);
33             byte[] buffer = ms.GetBuffer();
34             ms.Close();
35             return buffer;
36             //return Encoding.Unicode.GetString(buffer);
37         }
38         public static Msg Deserialize(byte[] buffer)
39         {
40             MemoryStream ms = new MemoryStream(buffer);
41             BinaryFormatter bf = new BinaryFormatter();
42             Msg msg = (Msg)bf.Deserialize(ms);
43             return msg;
44         }
45     }
46     /// <summary>
47     /// 傳輸結構
48     /// </summary>
49     public struct CopyDataStruct
50     {
51         public IntPtr dwData;
52         public int cbData;
53         [MarshalAs(UnmanagedType.LPStr)]
54         public string lpData;
55     }
56 }
View Code

 轉換幫助類:數組

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 namespace Dralee.AppTransferMsg.Common
 7 {
 8     // CreatedBy: Jackie Lee
 9     // CreatedOn: 2016-08-17
10     /// <summary>
11     /// 字節數組與字符串互轉
12     /// </summary>
13     public class HexConverter
14     {
15         /// <summary>
16         /// 字節數組轉
17         /// </summary>
18         /// <param name="buffer"></param>
19         /// <returns></returns>
20         public string ByteToString(byte[] buffer)
21         {
22             StringBuilder sb = new StringBuilder();
23             for(int i = 0; i < buffer.Length; ++i)
24             {
25                 sb.AppendFormat("{0:X2}", buffer[i]);
26             }
27             return sb.ToString();
28         }
29         /// <summary>
30         /// 字符串轉字節數組
31         /// </summary>
32         /// <param name="str"></param>
33         /// <returns></returns>
34         public byte[] StringToByte(string str)
35         {
36             if(string.IsNullOrEmpty(str) || str.Length % 2 != 0)
37             {
38                 return null;
39             }
40             byte[] buffer = new byte[str.Length / 2];
41             string hex;
42             int j = 0;
43             for(int i = 0; i < buffer.Length;++i)
44             {
45                 hex = new string(new char[] { str[j], str[j + 1]});
46                 buffer[i] = HexToByte(hex);
47                 j += 2;
48             }
49             return buffer;
50         }
51         /// <summary>
52         /// 雙字節字符轉byte
53         /// </summary>
54         /// <param name="hex"></param>
55         /// <returns></returns>
56         public byte HexToByte(string hex)
57         {
58             if (hex.Length > 2)
59                 return 0;
60             char[] hexs = hex.ToArray();
61             if(hexs.Length == 1)
62             {
63                 return (byte)NumByChar(hexs[0]);
64             }
65             else
66             {
67                 return (byte)(NumByChar(hexs[0]) * 16 + NumByChar(hexs[1]));
68             }
69         }
70         private byte NumByChar(char ch)
71         {
72             switch(ch)
73             {
74                 case '0': return 0;
75                 case '1': return 1;
76                 case '2': return 2;
77                 case '3': return 3;
78                 case '4': return 4;
79                 case '5': return 5;
80                 case '6': return 6;
81                 case '7': return 7;
82                 case '8': return 8;
83                 case '9': return 9;
84                 case 'A': return 10;
85                 case 'B': return 11;
86                 case 'C': return 12;
87                 case 'D': return 13;
88                 case 'E': return 14;
89                 case 'F': return 15;
90                 default:
91                     return 0;
92             }
93         }
94     }
95 }
View Code

API類:ide

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Runtime.InteropServices;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 namespace Dralee.AppTransferMsg.Common
 8 {
 9     public static class API
10     {
11         public const int WM_COPYDATA = 0x004A;
12         [DllImport("User32.dll", EntryPoint = "FindWindow")]
13         public static extern int FindWindow(string lpClassName, string lpWindowName);
14         /// <summary>
15         /// 發送消息
16         /// </summary>
17         /// <param name="hwnd">目標句柄</param>
18         /// <param name="msg"></param>
19         /// <param name="wParam">參數1</param>
20         /// <param name="lParam">參數2</param>
21         /// <returns></returns>
22         [DllImport("User32.dll", EntryPoint = "SendMessage")]
23         public static extern int SendMessage(int hwnd, int msg, int wParam, ref CopyDataStruct lParam);
24     }
25 }
View Code

發送端:函數

 1 private void btnSend_Click(object sender, EventArgs e)
 2 {
 3     Msg msg = new Msg { SentBy = txtSentBy.Text.Trim(), RcvBy = txtRcvBy.Text.Trim(), Message = txtMsg.Text.Trim(), SentOn = DateTime.Parse(txtSentOn.Text) };
 4     //long size = GC.GetTotalMemory(true);
 5     int hwnd = API.FindWindow(null, "(測試)->接收者");
 6     if (hwnd == 0)
 7         return;
 8     string msgStr = new HexConverter().ByteToString(Msg.Serialize(msg));
 9     CopyDataStruct cds;
10     cds.dwData = (IntPtr)100;
11     cds.cbData = (int)msgStr.Length + 1;
12     cds.lpData = msgStr;
13             
14     API.SendMessage(hwnd, API.WM_COPYDATA, 0,ref cds);
15 }
View Code

接收端,經過重寫以實現對消息監控:工具

 1 protected override void DefWndProc(ref Message m)
 2 {
 3     switch(m.Msg)
 4     {
 5         case API.WM_COPYDATA:
 6             CopyDataStruct cds = (CopyDataStruct)m.GetLParam(typeof(CopyDataStruct));
 7             //Msg msg = (Msg)m.GetLParam(typeof(Msg));
 8             byte[] buffer = new HexConverter().StringToByte(cds.lpData);
 9             Msg msg = Msg.Deserialize(buffer);
10             txtMsg.Text = msg.Message;
11             txtRcvBy.Text = msg.RcvBy;
12             txtSentBy.Text = msg.SentBy;
13             txtSentOn.Text = msg.SentOn.ToLongDateString();
14             break;
15         default:
16             base.DefWndProc(ref m);
17             break;
18     }
19 }
View Code

效果:測試

相關文章
相關標籤/搜索