本机多个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
觉得代码有用的朋友帮忙点下推荐呀~!-_-