Process.Exited 永远不会触发

问题描述 投票:0回答:1

我创建了一个通用类来执行控制台应用程序,同时将其输出重定向到我的表单中的

RichTextBox

代码工作得很好,但是

Process.Exited
事件永远不会触发,即使控制台应用程序在完成其功能后正常存在。

此外,

WaitForExit
似乎没有做任何事情,而且我在它之后编写的任何代码由于某种原因都不会执行。

这是课程(更新):

using System;
using System.Diagnostics;

public class ConsoleProcess
{
    private string fpath;
    public ConsoleProcess(string filePath)
    {
        fpath = filePath;
    }

    public void Run(string arguments)
    {
        var procInfo = new ProcessStartInfo()
        {
            FileName = fpath,
            Arguments = arguments,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            UseShellExecute = false,
            CreateNoWindow = true,
            WindowStyle = ProcessWindowStyle.Hidden
        };

        var proc = new Process() { EnableRaisingEvents = true, StartInfo = procInfo };

        proc.OutputDataReceived += Proc_DataReceived;
        proc.ErrorDataReceived += Proc_DataReceived;
        proc.Exited += Proc_Exited;

        proc.Start();
        proc.BeginOutputReadLine();
        proc.BeginErrorReadLine();
    }

    public event EventHandler<EventArgs>? ProcessExited;
    private void Proc_Exited(object? sender, EventArgs e)
    {
        ProcessExited?.Invoke(sender, e);
    }

    public event EventHandler<DataReceivedEventArgs>? DataReceived;
    private void Proc_DataReceived(object sender, DataReceivedEventArgs e)
    {
        DataReceived?.Invoke(sender, e);
    }
}

这是我在

Form
中使用的代码:

        ConsoleProcess process = new("console_app.exe");
        process.DataReceived += Process_DataReceived;
        process.ProcessExited += Process_Exited;

        private async void Execute()
        {
            await Task.Run(() =>
            {
                process.Run("--arguments");
            });
        }

        private void Process_DataReceived(object? sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            //do stuff
        }

        private void Process_Exited(object? sender, EventArgs e)
        {
            MessageBox.Show("Done");
        }

PS:我知道有几个关于这个问题的帖子,我已经检查过它们,但没有一个有帮助,所以我在这里。

c# winforms async-await process .net-5
1个回答
0
投票

要解决您面临的问题,请尝试添加

proc.WaitForExit();

代码

    ...
proc.Start();
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();

//added - wait for exit
proc.WaitForExit(); 
    ...

如果您想使用

Task
,请尝试以下操作:

注意:我将类

ConsoleProcess
重命名为
HelperProcess
,因为原来的名称似乎有些欺骗性。

创建新项目 - Windows 窗体应用程序

  • 姓名:
    ProcessTest
  • 目标框架:
    .NET 5

创建一个类(名称:HelperProcess.cs)

辅助进程

using System;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ProcessTest
{
    public class HelperProcess
    {
        public event EventHandler<EventArgs> ProcessExited;
        public event EventHandler<DataReceivedEventArgs> DataReceived;

        private string fPath;

        public HelperProcess(string filePath)
        {
            fPath = filePath;
        }

        public async Task Run(string arguments)
        {
            Debug.WriteLine($"fPath: {fPath}");

            var procInfo = new ProcessStartInfo()
            {
                FileName = fPath,
                Arguments = arguments,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                WindowStyle = ProcessWindowStyle.Hidden
            };

            using (Process proc = new Process() { EnableRaisingEvents = true, StartInfo = procInfo })
            {
                //subscribe to events
                proc.OutputDataReceived += Proc_DataReceived;
                proc.ErrorDataReceived += Proc_DataReceived;
                proc.Exited += Proc_Exited;

                //start
                proc.Start();

                //start reading
                proc.BeginOutputReadLine();
                proc.BeginErrorReadLine();

                //Debug.WriteLine("before proc.WaitForExitAsync");

                //wait for exit
                await proc.WaitForExitAsync();

                //Debug.WriteLine("after proc.WaitForExitAsync");

                //unsubscribe from events
                proc.OutputDataReceived -= Proc_DataReceived;
                proc.ErrorDataReceived -= Proc_DataReceived;
                proc.Exited -= Proc_Exited;
            }
        }

        private void Proc_Exited(object sender, EventArgs e)
        {
            //Debug.WriteLine("Proc_Exited");
            ProcessExited?.Invoke(sender, e);
        }

        private void Proc_DataReceived(object sender, DataReceivedEventArgs e)
        {
            //ToDo: add desired code

            //Debug.WriteLine($"Proc_DataReceived: {e.Data}");

            //if (DataReceived != null && !String.IsNullOrEmpty(e.Data))
            //{
            //    DataReceived.Invoke(sender, e);
            //}

            DataReceived?.Invoke(sender, e);
        }
    }
}

向 Form1 添加按钮(名称:btnRun)

  • 双击按钮添加
    Click
    事件处理程序

打开属性窗口

  • 在 VS 菜单中,点击 View
  • 选择属性窗口

向 Form1 添加

FormClosed
事件处理程序

  • 在属性窗口中,从下拉列表中选择Form1
  • 点击enter image description here
  • 双击 FormClosed 将事件处理程序添加到 Form1

表格1

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace ProcessTest
{
    public partial class Form1 : Form
    {
        private HelperProcess _process = null;
        public Form1()
        {
            InitializeComponent();

            string fPath = string.Empty;

            //environment variable windir has the same value as SystemRoot
            //use 'Sysnative' to access 64-bit files (in System32) if program is running as 32-bit process
            //use 'SysWow64' to access 32-bit files on 64-bit OS

            if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
                fPath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "Sysnative", "wbem", "wmic.exe");
            else
                fPath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "System32", "wbem", "wmic.exe");

            //create new instance
            _process = new HelperProcess(fPath);

            //subscribe to events
            _process.DataReceived += Process_DataReceived;
            _process.ProcessExited += Process_ProcessExited;
        }

        private async void btnRun_Click(object sender, EventArgs e)
        {
            Debug.WriteLine("before Execute");
            await Execute();
            Debug.WriteLine("after Execute");
        }

        private async Task Execute()
        {
            await _process.Run("process get");

            Debug.WriteLine("after _process.Run");
        }

        private void Process_ProcessExited(object sender, EventArgs e)
        {
            Debug.WriteLine("Main: Process_ProcessExited");
        }

        private void Process_DataReceived(object sender, DataReceivedEventArgs e)
        {
            Debug.WriteLine($"Main: Process_DataReceived: {e.Data}");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (_process != null)
            {
                //unsubscribe from events
                _process.DataReceived -= Process_DataReceived;
                _process.ProcessExited -= Process_ProcessExited;
            }
        }
    }
}

资源

© www.soinside.com 2019 - 2024. All rights reserved.