TOC

This article is currently in the process of being translated into Chinese (~91% done).

Misc:

Starting applications with the Process class

程序的众多功能中有一项非常有用的是运行其它程序。比如,可能会在程序中包含一个指向相应网站的链接,如果不想强迫用户自己把此链接URL敲入浏览器或拷贝/粘贴进去,就应该让该链接可点击,然后用用户的默认浏览器打开它。

本教程主要使用的是控制台程序,因为它们相对简单,能更好地展示语言的句法而不用涉及过多繁杂的内容。而上文提到的例子明显更倾向于图形用户界面(GUI),需要使用象WinForms或WPF这样的.NET GUI框架,不过从一个控制台程序中运行其它程序仍然很有用,即使现在没有用,学会了也没坏处,总有一天会用到。

使用Process类

要实例化其它程序 ,需要使用Process类。Process类在System.Diagnostics名空间中,因此需要先引用:

using System.Diagnostics;

最基本的用法是简单地使用静态方法Start()来运行一个程序 :

Process.Start("https://www.google.com/");

注意此处提供的是一个URL - 这里也可以是一个本地程序的路径,如,Notepad(如在Microsoft Windows操作系统上):

Process.Start(@"C:\Windows\notepad.exe");

两种方法都可行的原因是因为Process类仅仅是把此指令传递给操作系统,基本上等于对操作系统说“运行这个东西”。操作系统会检查传入的信息,看是否有支持此类信息的操作。如果传入的是个可执行文件的路径,就运行该程序 - 如果传入的是其它东西,如,一个URL(网络链接)或指向某类本地文件的路径,操作系统会试图使用某个相关的程序去处理这个文件或URL。这也表示在程序中可以运行一个指向本地文件夹的路径 - 如果用的是Windows操作系统,这会启动Windows文件浏览器(Windows File Explorer),并打开传入的路径。

使用参数启动程序

启动程序时能够传入一个或多个参数非常有用。控制台程序通常能够接收广泛的各类参数,不过Windows程序也能接收通过控制台传入的参数。比如,启动写字板(Notepad)程序时,可以传入需要打开编辑的文件作为参数,象这样:

Process.Start(@"C:\Windows\notepad.exe", @"C:\Windows\win.ini");

可以这样是因为Notepad程序本身就设计为要监视控制台命令行以接收参数 - 如果启动时有参数,它会使用第一个参数作为要打开的文件的路径。可以简单地把win.ini替换为任何想要打开的文件来测试看看!

使用ProcessStartInfo类

Process类是个很复杂的类,功能远非仅仅是启动程序。本文不会涉及其全部功能,而是主要关注其启动新进程的能力。启动进程时,有时需要对其行为多一点控制,这就需要用到ProcessStartInfo类了。这样可以传入的参数就不象使用Start()方法参数一样仅传入一个路径了,而是传入一个ProcessStartInfo类实例,象这样:

ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = @"C:\Windows\notepad.exe";
processStartInfo.Arguments = @"C:\Windows\win.ini";

Process.Start(processStartInfo);

此代码其实与前面的例子功能完全一样,因此这里先介绍几个ProcessStartInfo类有用的属性,除了前面例子用到的FilenameArguments属性之外,还有些属性能提供更多的控制:

WindowStyle

使用WindowStyle属性控制程序启动时的显示方式。例如,可以以最大化或最小化的方式启动程序,象这样:

processStartInfo.WindowStyle = ProcessWindowStyle.Minimized;

CreateNoWindow

CreateNoWindow属性的功能由其名称可看出:设置为true时,程序启动时不会生成窗口。这当然只与那些不需要用户交互界面就可以完成其功能的程序相关,比如,一个可以接收输入,然后用这些输入做某些操作,并把结果返回给调用程序的程序。

UseShellExecute

此属性允许控制是否使用系统shell来启动进程 - 否则进程会直接由可执行文件生成。在.NET Core之前的.NET framework中,此属性的默认值是true,但在.NET Core中默认值是false。后面会在扩展示例中用到此属性。

WorkingDirectory

使用此属性设置可执行内容的启动目录路径。不过,要注意其作用根据UseShellExecute属性设置为true还是false会有所不同。当UseShellExecute设置为true时,WorkingDirectory属性只简单指定可执行文件的位置,且调用方的工作目录也会成为被启动的进程的工作目录。当UseShellExecute设置为false时,WorkingDirectory属性不用于查找可执行文件 - 而是把其传递给启动的进程,有什么功能由新进程的上正文自行确定。

RedirectStandardInput,RedirectStandardOutput和RedirectStandardError

这几个属性设置为true时,可以把被启动的进程的输入/输出及错误信息重定向到调用进程。这些属性,比如,在与CreateNoWindow一起使用时就会很有用,因为可以启动进程,然后给其提供输入和/或从中接收错误信息和输出。在后面的最终示例中综合使用前面提到的属性时也会用到此属性。

综合示例

可以讨论的属性其实很多,但前面强调的这些属性无疑是最重要的。因此,这里会展示最终示例,把这几个刚才介绍过的技术用于实现一些很有意思的功能。首先,请先看一下完整示例代码,下面就会开始讲解此示例:

Console.WriteLine("Press any key to run CMD...");
Console.ReadKey();

ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = @"C:\Windows\system32\cmd.exe";
processStartInfo.Arguments = "/c date /t";

processStartInfo.CreateNoWindow = true;
processStartInfo.UseShellExecute = false;			
processStartInfo.RedirectStandardOutput = true;

Process process = new Process();
process.StartInfo = processStartInfo;
process.Start();

string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

Console.WriteLine("Current date (received from CMD):");
Console.Write(output);

示例开始时生成了一个ProcessStartInfo对象。使用FilenameArguments属性指定运行一个Windows命令行程序,具体为cmd.exe(默认的Windows命令行解释器)。需要运行的命令由Arguments指定 - 这里指定了带/t参数的date命令,只简单输出当前日期。

注意此处使用了三个前面讨论过的属性:CreateNoWindow = true(希望不用显示cmd窗口就能获取其输出),UseShellExecute = false(需要其直接执行指定的命令)和RedirectStandardOutput = false(同样,需要获取其输出)。

然后,程序创建Process实例,设置其StartInfo属性值,调用Start()方法启动进程。

接下来两行代码通过调用Process.StandardOutput.ReadToEnd()方法请求接收产生的输出。把此输出保存在一个字符串变量中,然后调用WaitForExit()方法,确保被启动的这个进程有机会完全运行结束。

最后两行代码简单地把收到的输入信息输出 - 应该就是当前日期。当然,对于输出当前日期这个功能来说这样做显然太过繁琐 - 本来一行代码就能搞定的事。但这个例子能展示出这种技术的强大功能,允许调用其它程序,并在调用方程序中使用其功能。

总结

Process类是个非常强大的工具,允许启动其它进程,甚至可以进行控制。本文只展示了其众多能力中的一部分,不过希望已经展示出了此工具的强大之处,有兴趣可以自行进一步去探索其它的功能。


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!