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运行完毕");
}

参考

相关文章
|
1月前
|
缓存 C# Windows
C#程序如何编译成Native代码
【10月更文挑战第15天】在C#中,可以通过.NET Native和第三方工具(如Ngen.exe)将程序编译成Native代码,以提升性能和启动速度。.NET Native适用于UWP应用,而Ngen.exe则通过预编译托管程序集为本地机器代码来加速启动。不过,这些方法也可能增加编译时间和部署复杂度。
|
5月前
|
存储 安全 Java
程序与技术分享:C#值类型和引用类型的区别
程序与技术分享:C#值类型和引用类型的区别
43 0
|
1月前
|
存储 C#
【C#】大批量判断文件是否存在的两种方法效率对比
【C#】大批量判断文件是否存在的两种方法效率对比
39 1
|
27天前
|
设计模式 程序员 C#
C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤
WinForm MDI 模式就像是有超能力一般,让多个子窗体井然有序地排列在一个主窗体之下,既美观又实用。不过,也要小心管理好子窗体们的生命周期哦,否则一不小心就会出现一些意想不到的小bug
|
1月前
|
XML 存储 安全
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
55 0
|
1月前
|
安全 API C#
C# 如何让程序后台进程不被Windows任务管理器强制结束
C# 如何让程序后台进程不被Windows任务管理器强制结束
63 0
|
2月前
|
C# 容器
C#中的命名空间与程序集管理
在C#编程中,`命名空间`和`程序集`是组织代码的关键概念,有助于提高代码的可维护性和复用性。本文从基础入手,详细解释了命名空间的逻辑组织方式及其基本语法,展示了如何使用`using`指令访问其他命名空间中的类型,并提供了常见问题的解决方案。接着介绍了程序集这一.NET框架的基本单位,包括其创建、引用及高级特性如强名称和延迟加载等。通过具体示例,展示了如何创建和使用自定义程序集,并提出了针对版本不匹配和性能问题的有效策略。理解并善用这些概念,能显著提升开发效率和代码质量。
98 4
|
1月前
|
XML 存储 缓存
C#使用XML文件的详解及示例
C#使用XML文件的详解及示例
88 0
|
1月前
|
API C#
C#实现Winform程序右下角弹窗消息提示
C#实现Winform程序右下角弹窗消息提示
82 0
|
2月前
|
Linux C# 开发者
Uno Platform 驱动的跨平台应用开发:从零开始的全方位资源指南与定制化学习路径规划,助您轻松上手并精通 C# 与 XAML 编程技巧,打造高效多端一致用户体验的移动与桌面应用程序
【9月更文挑战第8天】Uno Platform 的社区资源与学习路径推荐旨在为初学者和开发者提供全面指南,涵盖官方文档、GitHub 仓库及社区支持,助您掌握使用 C# 和 XAML 创建跨平台原生 UI 的技能。从官网入门教程到进阶技巧,再到活跃社区如 Discord,本指南带领您逐步深入了解 Uno Platform,并提供实用示例代码,帮助您在 Windows、iOS、Android、macOS、Linux 和 WebAssembly 等平台上高效开发。建议先熟悉 C# 和 XAML 基础,然后实践官方教程,研究 GitHub 示例项目,并积极参与社区讨论,不断提升技能。
91 2