目录

.Net程序间的通讯与控制

目录

如果有一个需求,用一个程序控制另一个程序,最简单的,比如用程序A打开程序B,这个想必平时都会用到,可以使用Process类及相关的方法。那么在打开B的时候发送一些参数,然后B根据这些参数做出一些反映,这该怎么实现?其实还是用Process。

发送端:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21

static void Main(string[] args)
{
	Console.WriteLine("请输入接收器路径:");
	string path = Console.ReadLine();
	Console.WriteLine("请输入接收器启动参数:");
	string para = Console.ReadLine();
	ProcessStartInfo pi = new ProcessStartInfo();
	pi.FileName = @path;
	pi.Arguments = para;

	try
	{
		Process.Start(pi);
	}
	catch
	{
		Console.WriteLine("找不到接收器或出现错误!");
	}
	Console.ReadKey();
}

接收端:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
static void Main(string[] args)
{
	if (args.Length == 0)
	{
		Console.WriteLine("未接到信息!");
	}
	else
	{
		foreach (string s in args)
		{
			Console.WriteLine(s);
		}
	}

	Console.ReadKey();
}

这样我们就可以用程序A启动程序B,根据A传入的参数,程序B做出相应的处理。**不过在WPF中,就没法直接用Main中的args参数了。**对于WPF,可以用下面的方式处理:

1.在App.xaml 中删除 StartupUri,并添加Startup

1
2
3
4
5
6
7
8
	<Application x:Class="WpfApplication65.App"
	             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	             Startup="Application_Startup" >
	    <Application.Resources>
	         
	    </Application.Resources>
	</Application>

2.在App.xaml.cs中填写startup的内容

1
2
3
4
5
6
7
8
9
private void Application_Startup(object sender, StartupEventArgs e)
{
	MainWindow mw = new MainWindow();
	foreach(string s in e.Args)
	{
		mw.txtShow.Text += s;
	}
	mw.Show();
}

这样就可以获取传入的参数了。

但是再改一下需求,我们不仅仅通过程序启动的时候传入参数,而是需要给一个已经启动的程序传入参数,那么就需要用进程通信了IPC了。IPC需要用到Windows API,下面将介绍一下WPF实现进程间的通信。

1.新建数据的结构体类库

新建一个类库,类库内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace DataStruct
{
	[StructLayout(LayoutKind.Sequential)]
	public struct DataStruct
	{
		public IntPtr dwData;
		public int cbData;  // 字符串长度
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpData; // 字符串
	}
}

2.新建信息帮助类库

新建一个类库,引用上一步的结构体类库,类库内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace MessageHelper
{
	public class MessageHelper
	{
		public const int WM_DOWNLOAD_COMPLETED = 0x00AA;
		public const int WM_COPYDATA = 0x004A;

		[DllImport("User32.dll", EntryPoint = "FindWindow")]
		public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

		[DllImport("User32.dll", EntryPoint = "SendMessage")]
		public static extern int SendMessage(IntPtr wnd, int msg, int wP, ref DataStruct.DataStruct cds);
	}
}

3.发送端

首先引用前两步的类库

发送有两种方式:

a.通过进程名

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var lstProcess = Process.GetProcessesByName(txtProcess.Text);
if (lstProcess.Length > 0)
{
	Process proc = lstProcess[0];
	DataStruct.DataStruct cds;
	cds.dwData = IntPtr.Zero;
	cds.lpData = txtMSG.Text;
	cds.cbData = System.Text.Encoding.Default.GetBytes(txtMSG.Text).Length + 1;

	int fromWindowHandler = 0;

	MessageHelper.MessageHelper.SendMessage(proc.MainWindowHandle, MessageHelper.MessageHelper.WM_COPYDATA, fromWindowHandler, ref cds);
}

注意:使用这种方法,如果窗体的ShowInTaskbar=false,也就是不在任务栏显示的话,那么是没有办法通过MainWindowHandle获取窗口的。

b.通过窗口名

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
IntPtr hwnd = MessageHelper.MessageHelper.FindWindow(null, txtTitle.Text);

if (hwnd != IntPtr.Zero)
{
	DataStruct.DataStruct cds;
	cds.dwData = IntPtr.Zero;
	cds.lpData = txtMSG.Text;
	cds.cbData = System.Text.Encoding.Default.GetBytes(txtMSG.Text).Length + 1;
	// 消息来源窗体
	int fromWindowHandler = 0;
	MessageHelper.MessageHelper.SendMessage(hwnd, MessageHelper.MessageHelper.WM_COPYDATA, fromWindowHandler, ref cds);
}

注意:使用这种方法,如果有多个窗口的Title是一样的,也是会有冲突的。

4.接收端

首先还是先引用前两步的类库。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public MainWindow()
{
	InitializeComponent();
	Loaded += new RoutedEventHandler(Window_Loaded);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
	(PresentationSource.FromVisual(this) as HwndSource).AddHook(new HwndSourceHook(this.WndProc));
}

IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{

	if (msg == MessageHelper.MessageHelper.WM_COPYDATA)
	{

		DataStruct.DataStruct cds = (DataStruct.DataStruct)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(DataStruct.DataStruct));

		txtShow.Text = cds.lpData;

	}

	return hwnd;

}

程序下载