Process.Exited 永远不会触发

发布于 2025-01-20 16:21:18 字数 2294 浏览 3 评论 0 原文

我创建了一个通用类来执行控制台应用程序,同时将其输出重定向到表单中的 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:我知道有几个关于这个问题的帖子,我已经检查过它们,但没有一个有帮助,所以我在这里。

I created a generic class to execute a console application while redirecting its output to a RichTextBox in my form.

The code works just fine, but the Process.Exited event never fires even though the console application exists normally after it completes it function.

Also, WaitForExit doesn't seem to do anything and any code I write after it is never executed for some reason.

Here's the class (updated):

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);
    }
}

Here's the code I use in the 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: I'm aware that there are several posts about this issue, and I've checked them, but none of them helped, so here I am.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦断已成空 2025-01-27 16:21:18

要解决您所面临的问题,请尝试添加 Proc.WaitForexit();

代码

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

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

如果要使用 task ,请尝试以下内容:

Note :我将class consoleprocess 重命名为<代码> HelperProcess 作为原始名称似乎有些欺骗性。

创建一个新项目 - Windows表单应用程序

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

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

helperProcess

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)

  • 双击按钮添加单击 event> event handler

打开属性窗口

  • 在vs菜单中,单击查看
  • 选择属性窗口

添加 formclosed 事件处理程序to form1

  • in属性窗口,从下拉下单击
  • “在此处输入图像描述”
  • double-click form clocclosed 将事件处理程序添加到Form1

form1 strong>:

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;
            }
        }
    }
}

资源

To solve the issue that you're facing, try adding proc.WaitForExit();.

Code:

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

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

If you want to use Task, then try the following:

Note: I renamed class ConsoleProcess to HelperProcess as the original name seems somewhat deceptive.

Create a new project - Windows Forms App

  • Name: ProcessTest
  • Target Framework: .NET 5

Create a class (name: HelperProcess.cs)

HelperProcess:

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(
quot;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(
quot;Proc_DataReceived: {e.Data}");

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

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

Add button to Form1 (name: btnRun)

  • Double-click button to add Click event handler

Open Properties Window

  • In VS menu, click View
  • Select Properties Window

Add FormClosed event handler to Form1

  • In Properties Window, select Form1 from the drop-down
  • Click enter image description here
  • Double-click FormClosed to add the event handler to Form1

Form1:

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(
quot;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;
            }
        }
    }
}

Resources:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文