C#使用Process打开外部程序或外部文件的使用总结

简介: 执行一个外部的第三方应用的原理,和调用cmd执行命令是一样的,只不过可以添加程序的启动参数(`StartInfo.Arguments`)等。调用第三方应用,在其启动后,关于程序的操作、处理、是否...

调用第三方应用程序

执行一个外部的第三方应用的原理,和调用cmd执行命令是一样的。只不过可以添加程序的启动参数(StartInfo.Arguments)等。

调用其他应用程序,和调用cmd执行命令行也有所区别。通常调用cmd是为了执行完某条或某几条命令,执行完就结束了。而调用第三方应用,在其启动后,关于程序的操作、处理、是否有输入和输出,不同的程序有着不同的情况,不同需求和不同人的操作也会不同。可以尝试使用之前cmd的调用代码执行第三方程序,就能感受到很大不同,尤其是StandardOutput读取输出,会一直等待。

因此,调用第三方程序,更多的是启动第三方程序,然后让用户去操作;或者针对某特定的程序,启动后通过代码准确执行特定的步骤,即自动化操作,然后关闭应用(这时涉及到自动化的部分[ui自动化、输入输出自动化]),甚至需要多线程,当前线程使用Process打开应用,另一个线程操作应用等。

所以,目前难以有比较通用的方式,但是可以写一个启动方法,启动第三方软件,设置等不等待软件运行结束、获不获取输出(如果有的话)。后面更多的应该了解Process的使用。

如下,采用下面的方式启动一个可执行程序。根据需要是否有启动参数、是否等待结束、是否获取输出等:

/// <summary>
/// 执行外部exe程序
/// </summary>
public static class ExecApp
{
        /// <summary>
        /// 启动一个可执行程序,执行参数为arguments。启动一个关联的子进程,并且等待子进程的处理返回【一种有限的方式运行其他程序】
        /// 注意,如果是等待结束的情况下,必须保证会自动结束,或者最后会关闭/退出程序
        /// </summary>
        /// <param name="appPath"></param>
        /// <param name="arguments">启动参数</param>
        /// <param name="waitComplete">是否等待结束,默认false,启动程序后就结束不再管理;若为true,则必须保证会执行结束,或者手动关闭/退出程序,否则一直等待</param>
        /// <param name="getOuput">是否获取输出结果,waitComplete为true时,true获取输出结果才有效,并且要确保程序有输出,否则会一直等待</param>
        /// <returns></returns>
        public static async Task<ExecResult> StartExecutAsync(string appPath,string arguments=null, bool waitComplete= false, bool getOuput=false)
        {
            using (Process p = new Process())
            {
                var result = new ExecResult();
                try
                {
                    p.StartInfo.FileName = appPath;
                    p.StartInfo.Arguments = arguments;
                    p.StartInfo.UseShellExecute = false;        //设置false只能启动一个程序
                    p.StartInfo.RedirectStandardInput = false;  
                    p.StartInfo.RedirectStandardOutput = getOuput;  //由调用程序获取输出信息
                    p.StartInfo.RedirectStandardError = getOuput;   //重定向标准错误输出
                    p.StartInfo.CreateNoWindow = false;          //显示程序窗口

                    //p.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;

                    p.Start();//启动程序执行

                    if (waitComplete)
                    {
                        if (getOuput)
                        {
                            // 获取输出【确保程序有输出,否则会一直等待】
                            result.Output = await p.StandardOutput.ReadToEndAsync();
                            result.Error = await p.StandardError.ReadToEndAsync();
                        }

                        p.WaitForExit();//等待程序执行完退出进程。应在最后调用
                    }
                    p.Close();
                }
                catch (Exception ex)
                {
                    result.ExceptError = ex;
                }
                return result;
            }
        }
}

新建项目ExecAppTest,用于测试执行外部程序。

如下测试执行。

//var result= await ExecApp.StartExecutAsync(@"C:\WINDOWS\system32\cmd.exe");
var result= await ExecApp.StartExecutAsync(@"C:\WINDOWS\system32\cmd.exe",waitComplete:true,getOuput:true);
MessageBox.Show($"{result.Output}");

Process进程类介绍和使用

Process打开一个文档或文件、启动一个程序

Process可以使用默认应用打开一个与其文件类型(后缀)关联的任何文档。比如打开以为文本文档、打开一个图片文件、打开一个url地址等。

Process.Start("www.bing.com");

Process.Start("my.png");

Process.Start(@"C:\WINDOWS\system32\cmd.exe");

Process.Start("explorer.exe", @"c:/"); //用资源管理器打开C:/

获取进程中的多个模块:

var mList = Process.GetCurrentProcess().Modules;
foreach (ProcessModule m in mList)
{
    Console.WriteLine(string.Format("ModuleName is {0} \t ModuleURL  is {1} \t ModuleVersion is {2}", m.ModuleName, m.FileName, m.FileVersionInfo.FileVersion));
}

ProcessStartInfo进程启动信息

ProcessStartInfo用于设置进程其实的一些初始信息,比如启动参数(Arguments)、工作目录(WorkingDirectory)、是否使用系统Shell(UseShellExecute)、是否显示窗口(CreateNoWindow)\窗口的样式状态(WindowStyle)、重定向输入输出、输出的编码(StandardOutputEncoding)等

ProcessStartInfo Class可以查看更多的启动信息设置。

Process.StartInfo属性就是ProcessStartInfo,可以直接创建实例使用。

也可以创建ProcessStartInfo对象,所谓进程Process.Start()启动时的参数。

// 启动一个隐藏窗口的程序
ProcessStartInfo psi = new ProcessStartInfo()
{
    FileName= fileName,
    Arguments = arguments,
    WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(psi);

ProcessStartInfo.UseShellExecuteProcessStartInfo.WorkingDirectoryProcessStartInfo.ErrorDialog

  • ProcessStartInfo.UseShellExecute=false允许重定向输入、输出和错误流。但是,此时只能使用Process对象打开可执行程序。

UseShellExecute的关键字shell表示图形shell(壳),而不是命令shell(如bash或sh),使用它可以让用户启动图形应用或打开文档。

UserName非空时,UseShellExecute必须为false,否则报错InvalidOperationException

  • 当使用操作系统shell启动进程时(UseShellExecute=true),可以启动任何文档(包括可执行程序。只要注册关联了文件类型就行),并在文件上执行操作(比如使用Process对象打印)。

如果ErrorDialog=true,则UseShellExecute必须为true;如果WindowStyle=ProcessWindowStyle.Hidden,UseShellExecute也必须为true。

UseShellExecute 在.NET Framework中的默认值为true;.NET Core中为false。

ProcessStartInfo.ErrorDialog表示进程无法启动时是否显示对话框提醒。

UseShellExecute的取值不同,WorkingDirectory也会有所不同。

如果UseShellExecute为true, WorkingDirectory表示可执行程序的位置;

UseShellExecutefalse时,WorkingDirectory由启动的process对象使用。当UseShellExecute为false时,FileName可以是可执行文件的绝对路径,也可以是系统PATH环境变量指定的文件夹中找到的简单的可执行程序名称。

也就是对于cmd的调用,useshellexecute=false时,FileName可以直接指定为cmd.execmd即可。

WorkingDirectory工作目录是一个非常拥有的属性,UseShellExecute为false时一定要指定正确(通常为可执行程序的所在路径,即要启动的进程的工作目录)。

进程退出、标准输出和错误输出事件

  • Process.OutputDataReceived事件用于接受标准输出。上面的多个命令行执行的代码已有使用。
  • Process.ErrorDataReceived事件用于接受错误输出。上面的多个命令行执行的代码已有使用。
  • Process.Exited事件用于监听外部进程是否退出,可以避免WaitForExit()的线程阻塞。在结束事件中处理结束后的操作。Exited事件的启用,需要设置EnableRaisingEvents=true

比如下面,打开记事本程序,然后在Exited事件方法中处理其关闭后的操作,不阻塞当前线程的其他操作、

Process process = new Process();
process.StartInfo.FileName = @"C:\Windows\Notepad.exe";// process.StartInfo.FileName = "Notepad";
process.EnableRaisingEvents = true;
process.Exited += Process_Exited;
process.Start();

//...............

private void Process_Exited(object sender, EventArgs e)
{
    //Exited事件处理代码,外部程序退出后激活,可以执行相关操作
    MessageBox.Show("Notepad.exe运行完毕");
}

参考

相关文章
|
28天前
|
XML C# 数据格式
使用C#操作XML文件
使用C#操作XML文件
11 0
|
1月前
|
C#
C# 文件操作(全部) 追加、拷贝、删除、移动文件、创建目录
C# 文件操作(全部) 追加、拷贝、删除、移动文件、创建目录
21 0
|
3月前
|
C#
C#读取html文件
C#读取html文件
28 3
|
3月前
|
C# 开发者
C# 10.0中的文件范围命名空间:简化代码组织的新方式
【1月更文挑战第18天】C# 10.0引入了文件范围的命名空间,这是一种新的语法糖,用于更简洁地组织和管理代码。文件范围命名空间允许开发者在每个文件的基础上定义命名空间,而无需显式使用花括号包裹整个文件内容。本文将深入探讨文件范围命名空间的工作原理、使用场景以及它们为C#开发者带来的便利。
|
3月前
|
C# 开发者
C# 9.0中的模块初始化器:程序启动的新控制点
【1月更文挑战第14天】本文介绍了C# 9.0中引入的新特性——模块初始化器(Module initializers)。模块初始化器允许开发者在程序集加载时执行特定代码,为类型初始化提供了更细粒度的控制。文章详细阐述了模块初始化器的语法、用途以及与传统类型初始化器的区别,并通过示例代码展示了如何在实际项目中应用这一新特性。
|
3月前
|
编译器 C# 开发者
C# 9.0中的顶级语句:简化程序入口的新特性
【1月更文挑战第13天】本文介绍了C# 9.0中引入的顶级语句(Top-level statements)特性,该特性允许开发者在不使用传统的类和方法结构的情况下编写简洁的程序入口代码。文章详细阐述了顶级语句的语法、使用场景以及与传统程序结构的区别,并通过示例代码展示了其在实际应用中的便捷性。
|
4月前
|
IDE C# 开发工具
C# | 多线程批量下载文件(创建N个线程同时批量下载文件,只需要几行代码而已)
批量下载文件时使用多线程可以有效缩短完成时间,本文将讲解如何使用C#+CodePlus扩展库快速完成多线程的文件下载。 大部分代码由IDE自动生成,需要我们自己编写的代码正好**10行**。也就是说,只需要10分钟,就可以手撸一个多线程的批量下载器。
80 0
C# | 多线程批量下载文件(创建N个线程同时批量下载文件,只需要几行代码而已)
|
24天前
|
安全 数据处理 C#
C# Post数据或文件到指定的服务器进行接收
C# Post数据或文件到指定的服务器进行接收
|
24天前
|
C# 开发工具 数据安全/隐私保护
C#实现基于Word保护性模板文件的修改
C#实现基于Word保护性模板文件的修改
|
28天前
|
Java C# 开发工具
第一个C#程序
第一个C#程序
12 0