在实际项目应用中,经常会需要本机中不同的进程相互直接需要通信。
典型应用场景:
剪切板在不同应用程序间操作。
控制程序给予第三方程序通信控制接口,如播放器控制开关等。
在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效果是一样的。
代码戳:http://files.cnblogs.com/tmywu/ProcessCommunication.7z
觉得代码有用的朋友帮忙点下推荐呀~!-_-
|