首页 新闻 会员 周边

C# WinForm 启动并获取另一个控制台进程的输出

0
悬赏园豆:30 [已关闭问题] 关闭于 2021-09-17 16:43

背景

   有一个这样的exe文件,起来之后长这个样子:

            控制台进程
   然后我写了个WinForm程序,通过调用这个exe进行处理,长这样:

需求

    我想通过WinForm程序启动这个exe文件,并获取到它的进程对象。因为它这个是控制台应用,所以我能拿到黑窗口里输出的内容,并显示在界面右侧的状态里。

问题

  • 启动exe,获取到进程对象之后,由于这个进程处理时间比较长,会一直阻塞界面,界面卡死不响应操作;放线程中启动这个exe,并获取进程对象,则会有异常“System.InvalidOperationException”类型的未经处理的异常在 System.dll 中发生 StandardError 尚未重定向。

  • 要获取到进程在控制台的输出

我的代码

  • ProcessUtils 用来做进程启动
    public class ProcessUtils
    {
        private const string exeName = "./realesrgan-ncnn-vulkan.exe";
        private const string exeParam = " -i \"{0}\" -o \"{1}\" -n {2}";

        /// <summary>
        /// 启动进程进行图片的处理
        /// </summary>
        /// <param name="inputFile">输入图片的路径</param>
        /// <param name="outPutFile">输出图片的路径</param>
        /// <returns>进程对象</returns>
        public static Process ProcessImage(string inputFile, string outPutFile, string param)
        {
            Process process = new Process();
            process.StartInfo.FileName = Path.GetFullPath(exeName);
            string parameter = string.Format(exeParam, inputFile, outPutFile, param);
            process.StartInfo.Arguments = parameter;

            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardError = true;// 将控制台输出重定向,可以通过进程对象来获取到黑窗口中的输出

            process.Start();
            return process;
        }
    }
  • 调用进程的代码
        private void StartClearPicture(object sender, EventArgs e)
        {
            string inputDir = InputDirTextbox.Text.Trim();
            string outputDir = OutPutDirTextbox.Text.Trim();
            string param = NormalRadioBtn.Checked ? NormalRadioBtn.Tag.ToString() : AnimeRadioBtn.Tag.ToString();

            if (!Directory.Exists(outputDir))
            {
                Directory.CreateDirectory(outputDir);
            }
            if (!outputDir.EndsWith(@"\"))
            {
                outputDir+=@"\";
            }

            ListView.ListViewItemCollection items = this.fileList.Items;
            Process process = null;
            for (int i = 0; i < items.Count; i++)
            {
                var item = items[i];
                string filename = item.Text;
                //Process process = ProcessUtils.ProcessImage(item.Tag.ToString(), outputDir + filename, param);//这样写卡UI,界面必须等进程执行完才会响应用户操作

                process = StartProcess(item, outputDir, filename, param);//启动线程并拿到进程对象,这样写会有异常         “System.InvalidOperationException”类型的未经处理的异常在System.dll 中发生              StandardError 尚未重定向。
                ShowProgress(item, process);//展示处理进度
                process.WaitForExit();//等待当前进程处理完退出后处理下一条
            }
        }
  • 牵扯到的方法
        /// <summary>
        /// 启动进程
        /// </summary>
        /// <param name="item">界面中的一条</param>
        /// <param name="outputDir">输出目录</param>
        /// <param name="filename">输入文件名</param>
        /// <param name="param">进程的参数</param>
        /// <returns>进程对象</returns>
        private Process StartProcess(ListViewItem item,string outputDir,string filename,string param)
        {
            Process process = new Process();
            new Thread(() =>
            {
                process = ProcessUtils.ProcessImage(item.Tag.ToString(), outputDir + filename, param);
                while (!process.Responding)//等进程有响应再返回进程对象
                {
                    Thread.Sleep(100);
                }
            }).Start();
            return process;
        }

        /// <summary>
        /// 显示处理进度
        /// </summary>
        /// <param name="item">界面的一条数据</param>
        /// <param name="process">进程对象</param>
        private void ShowProgress(ListViewItem item,Process process)
        {
            new Thread(() => {
                StreamReader standardError = process.StandardError;
                while (!process.HasExited)
                {
                    while(!standardError.EndOfStream){
                        string str = standardError.ReadLine();
                        Console.WriteLine(str);//这里是可以拿到黑窗口的输出
                        this.BeginInvoke(new MethodInvoker(() => { SetProgress(item, str); }));
                    }
                }
                this.BeginInvoke(new MethodInvoker(() => { SetProgress(item, "100%"); }));
                standardError.Close();
            }).Start();
        }

        /// <summary>
        /// 改界面内容
        /// </summary>
        /// <param name="item">在处理的那一条</param>
        /// <param name="str">要改的内容</param>
        private void SetProgress(ListViewItem item, string str)
        {
            item.SubItems[2].Text = str;
            if (str.Contains("100%"))
            {
                item.BackColor = Color.FromArgb(ComponentColor.LightGreen);
            }
        }
echo_lovely的主页 echo_lovely | 小虾三级 | 园豆:1437
提问于:2021-09-17 16:13
< >
分享
所有回答(1)
0

卡界面是因为这句话process.WaitForExit();//等待当前进程处理完退出后处理下一条

echo_lovely | 园豆:1437 (小虾三级) | 2021-09-17 16:43
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册