本机多个WPF应用程序进行进程间通信的解决方案

  在实际项目应用中,经常会需要本机中不同的进程相互直接需要通信。

  典型应用场景:

    剪切板在不同应用程序间操作。

    控制程序给予第三方程序通信控制接口,如播放器控制开关等。

  在Windows操作系统中,进程间相互通信的方式至少可以列5种以上,本文讲述在WPF环境下比较简便的解决方案:

  •   1.WCF NetNamedPipeBinding
  •   2.Win32  

  1.WCF NetNamedPipeBinding

  NetNamedPipeBinding适用于本机间进程通信,基于命名管道来进行消息传递。

  Link:http://msdn.microsoft.com/zh-cn/library/ms752247.aspx

  引用System.ServiceModel,定义一组端对端的通信接口:

 1 namespace IPCInterface
 2 {
 3     [ServiceContract(SessionMode = SessionMode.Allowed)]
 4     public interface IC2SMessages {
 5         [OperationContract(IsOneWay = true)]
 6         void Register(Guid clientID);
 7 
 8         [OperationContract(IsOneWay = true)]
 9         void DisplayCommandOnServer(string text);
10     }
11 }
12 
13 namespace IPCInterface {
14     [ServiceContract(SessionMode = SessionMode.Allowed)]
15     public interface IS2CMessages {
16         [OperationContract(IsOneWay = true)]
17         void CommandInClient(string text);
18     }
19 }

  

  在发送端实现:

  

 1 namespace WinTarget {
 2     [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.Single)]
 3     public partial class MainWindow : Window, IC2SMessages {
 4         ServiceHost _serverHost;
 5         List<Guid> _registeredClients = new List<Guid>();
 6 
 7         public MainWindow() {
 8             InitializeComponent();
 9 
10             _serverHost = new ServiceHost(this);
11 
12             _serverHost.AddServiceEndpoint((typeof(IC2SMessages)), new NetNamedPipeBinding(), "net.pipe://localhost/Server");
13             _serverHost.Open();
14         }
15 
16         private void SendText(Guid client, string text) {
17             using (ChannelFactory<IS2CMessages> factory = new ChannelFactory<IS2CMessages>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/Client_" + client.ToString()))) {
18                 IS2CMessages serverToClientChannel = factory.CreateChannel();
19                 try {
20                     serverToClientChannel.CommandInClient(text);
21                 } catch (Exception ex) {
22                     MessageBox.Show(ex.ToString());
23                 } finally {
24                     CloseChannel((ICommunicationObject)serverToClientChannel);
25                 }
26             }
27         }
28 
29         private void CloseChannel(ICommunicationObject channel) {
30             try {
31                 channel.Close();
32             } catch (Exception ex) {
33                 MessageBox.Show(ex.ToString());
34             } finally {
35                 channel.Abort();
36             }
37         }
38 
39         public void Register(Guid clientID) {
40             if (!_registeredClients.Contains(clientID)) {
41                 _registeredClients.Add(clientID);                
42             }
43         }
44 
45         public void DisplayCommandOnServer(string text) {
46             lbmessage.Content = text;
47         }
48 
49         private void Play_Click(object sender, RoutedEventArgs e) {
50             foreach (Guid client in _registeredClients) {
51                 SendText(client, "Play");
52             }
53         }
54 
55         private void Pause_Click(object sender, RoutedEventArgs e) {
56             foreach (Guid client in _registeredClients) {
57                 SendText(client, "Pause");
58             }
59         }
60     }
61 }

  接受端实现:

 1 namespace WinSource {
 2     [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.Single)]
 3     public partial class MainWindow : Window, IS2CMessages {
 4         Guid _clientID;
 5         ServiceHost _clientHost;
 6 
 7         public MainWindow() {
 8             InitializeComponent();
 9 
10             _clientID = Guid.NewGuid();
11             _clientHost = new ServiceHost(this);
12 
13             _clientHost.AddServiceEndpoint((typeof(IS2CMessages)), new NetNamedPipeBinding(), "net.pipe://localhost/Client_" + _clientID.ToString());
14             _clientHost.Open();
15 
16             this.Loaded += OnLoaded;
17         }
18 
19         void OnLoaded(object sender, RoutedEventArgs e) {
20             this.Dispatcher.BeginInvoke(new Action(() => {
21                 Register(_clientID);
22             }));
23 
24             media.LoadedBehavior = MediaState.Manual;
25             media.Source = new Uri(@"D:\Test\IMG_0245.MOV");
26             media.Play();
27         }
28 
29 
30         public void Register(Guid clientID) {
31             using (ChannelFactory<IC2SMessages> factory = new ChannelFactory<IC2SMessages>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/Server"))) {
32                 IC2SMessages clientToServerChannel = factory.CreateChannel();
33                 try {
34                     clientToServerChannel.Register(clientID);
35                     clientToServerChannel.DisplayCommandOnServer(string.Format("+Client:{0}", clientID.ToString()));
36                 } catch (Exception ex) {
37                     MessageBox.Show(ex.ToString());
38                 } finally {
39                     CloseChannel((ICommunicationObject)clientToServerChannel);
40                 }
41             }
42         }
43 
44         private void CloseChannel(ICommunicationObject channel) {
45             try {
46                 channel.Close();
47             } catch (Exception ex) {
48                 MessageBox.Show(ex.ToString());
49             } finally {
50                 channel.Abort();
51             }
52         }
53 
54         public void CommandInClient(string text) {
55             if (text == "Play") {
56                 media.Play();
57             } else {
58                 media.Pause();
59             }
60         }
61     }
62 }

  

  执行效果:

  

  2.Win32

  发送端引用 User32.dll SendMessage和FindWindow

  MessageHelper类:

 1     public class MessageHelper {
 2         public const int WM_COPYDATA = 0x004A;
 3 
 4         [DllImport("User32.dll", EntryPoint = "SendMessage")]
 5         private static extern int SendMessage
 6         (
 7         IntPtr hWnd,                   //目标窗体句柄
 8         int Msg,                       //WM_COPYDATA
 9         int wParam,                    //自定义数值
10         ref  CopyDataStruct lParam     //结构体
11         );
12 
13         [DllImport("User32.dll", EntryPoint = "FindWindow")]
14         public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
15 
16         public static void SendMessage(string windowName, string strMsg) {
17 
18             if (strMsg == null) return;
19 
20             IntPtr hwnd = FindWindow(null, windowName);
21 
22             if (hwnd != IntPtr.Zero) {
23                 CopyDataStruct cds;
24 
25                 cds.dwData = IntPtr.Zero;
26                 cds.lpData = strMsg;
27 
28                 cds.cbData = System.Text.Encoding.Default.GetBytes(strMsg).Length + 1;
29 
30                 int fromWindowHandler = 0;
31                 SendMessage(hwnd, WM_COPYDATA, fromWindowHandler, ref  cds);
32             }
33         }
34 
35         public static void SendMessageByProcess(string processName, string strMsg) {
36             if (strMsg == null) return;
37             var process = Process.GetProcessesByName(processName);
38             if (process.FirstOrDefault() == null) return;
39             var hwnd = process.FirstOrDefault().MainWindowHandle;
40             if (hwnd == IntPtr.Zero) return;
41 
42             if (hwnd != IntPtr.Zero) {
43                 CopyDataStruct cds;
44 
45                 cds.dwData = IntPtr.Zero;
46                 cds.lpData = strMsg;
47 
48                 cds.cbData = System.Text.Encoding.Default.GetBytes(strMsg).Length + 1;
49 
50                 int fromWindowHandler = 0;
51                 SendMessage(hwnd, WM_COPYDATA, fromWindowHandler, ref  cds);
52 
53             }
54         }
55         
56         [StructLayout(LayoutKind.Sequential)]
57         public struct CopyDataStruct {
58             public IntPtr dwData;
59             public int cbData;
60 
61             [MarshalAs(UnmanagedType.LPStr)]
62             public string lpData;
63         }
64     }

  发送端发送消息:

1 MessageHelper.SendMessageByProcess("WinSource", "Play");
2 
3 MessageHelper.SendMessageByProcess("WinSource", "Pause");

  

  接受端MessageHelper类

 1     public class MessageHelper {
 2         public const int WM_COPYDATA = 0x004A;
 3     }
 4 
 5 
 6     [StructLayout(LayoutKind.Sequential)]
 7     public struct CopyDataStruct {
 8 
 9         public IntPtr dwData;
10 
11         public int cbData;//字符串长度
12 
13         [MarshalAs(UnmanagedType.LPStr)]
14         public string lpData;//字符串
15     }

  接受端接受另一进程消息,并做处理动作

 

 1         void MainWindow_Loaded(object sender, RoutedEventArgs e) {
 2             (PresentationSource.FromVisual(this) as HwndSource).AddHook(new HwndSourceHook(this.WndProc));
 3             if (Application.Current.Properties["ArbitraryArgName"] != null) {
 4                 try {
 5                     string fname = Application.Current.Properties["ArbitraryArgName"].ToString();
 6                     midea.Source = new Uri(fname);
 7                     midea.Play();
 8                     Status = true;
 9                 } catch (Exception ex) {
10                     MessageBox.Show(ex.ToString());
11                 }
12             }
13 
14 
15         }
16 
17         IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
18             if (msg == MessageHelper.WM_COPYDATA) {
19                 CopyDataStruct cds = (CopyDataStruct)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(CopyDataStruct));
20                 if (cds.lpData == "Play") {
21                     if (Status) {
22                         midea.Pause();
23                         Status = false;
24                     } else {
25                         midea.Play();
26                         Status = true;
27                     }
28                 }
29             }
30             return hwnd;
31         }

  这样达到的效果和使用WCF NamedPipeBinding效果是一样的。 

  代码戳:https://files.cnblogs.com/tmywu/ProcessCommunication.7z

  

  觉得代码有用的朋友帮忙点下推荐呀~!-_-

 

  

posted @ 2013-05-09 17:10  老鱼_678  阅读(6075)  评论(3编辑  收藏  举报