• 本机多个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

      

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

      

  • 相关阅读:
    iBase4J部署总结
    就像我爱你,不仅仅是今天
    10年千亿美元,紫光集团目标跻身全球前五的存储器企业
    ddd
    微信的API都是通过https调用实现的,分为post方法调用和get方法调用。不需要上传数据的采用get方法(使用IntraWeb开发)
    管道通信实例(A程序作为服务器,不断从B程序接收数据,并发送到C程序中)
    HTTP协议中的短轮询、长轮询、长连接和短连接
    细说gulp
    Linux IO 调度器
    SPARK如何使用AKKA实现进程、节点通信
  • 原文地址:https://www.cnblogs.com/tmywu/p/3069279.html
Copyright © 2020-2023  润新知