确保在应用程序退出时终止来自线程的进程运行的可执行文件

时间:2014-11-24 13:34:48

标签: c# multithreading process console executable

我正在创建CaptureConsole类,如下所示:

public class CaptureConsole
{
    private string ExecutableName;
    private string[] Parameters;

    private DataReceivedEventHandler OnCaptureOutput;
    private DataReceivedEventHandler OnCaptureError;

    public CaptureConsole(string _executableName, string[] _parameters, DataReceivedEventHandler _onCaptureOutput, DataReceivedEventHandler _onCaptureError)
    {
        this.ExecutableName = _executableName;
        this.Parameters = _parameters;
        this.OnCaptureOutput = _onCaptureOutput;
        this.OnCaptureError = _onCaptureError;
    }

    public void Run()
    {
        ProcessStartInfo startInfo = new ProcessStartInfo()
        {
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            FileName = this.ExecutableName
        };

        // Parsing arguments
        for (int i = 0; i < this.Parameters.Length; i++)
        {
            if (i == 0)
                startInfo.Arguments = this.Parameters[0];
            if (i > 0)
            {
                startInfo.Arguments += " ";
                startInfo.Arguments += this.Parameters[i];
            }
        }

        Process process = new Process()
        {
            StartInfo = startInfo
        };
        process.OutputDataReceived += this.OnCaptureOutput;
        process.ErrorDataReceived += this.OnCaptureError;
        process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        process.StartInfo.CreateNoWindow = true;
        process.EnableRaisingEvents = true;

        Thread processThread = new Thread(() =>
        {
            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
            //process.WaitForExit();
        }) { IsBackground = true };

        processThread.Start();
    }
}

并像这样使用它:

        private void button1_Click(object sender, EventArgs e)
    {
        const string exeName = "ping.exe";
        string[] parameters = new string[] { "127.0.0.1", "-t" };
        CaptureConsole RunConsole = new CaptureConsole(exeName, parameters, ShowOutput, ShowError);
        RunConsole.Run();
    }

    void ShowOutput(object sender, DataReceivedEventArgs e)
    {
        if (e.Data != null)
            this.InvokeEx(x => x.listBox1.Items.Add(e.Data));
    }

    private void ShowError(object sender, DataReceivedEventArgs e)
    {
        if (e.Data != null)
            this.InvokeEx(x => x.listBox1.Items.Add(e.Data));
    }

这会按照需要运行,但我注意到如果我关闭应用程序,conhost.exe和ping.exe仍在任务管理器中运行,因为我使用-t参数进行ping操作。如何在应用程序关闭时确保我运行的可执行文件(在我的情况下为ping.exe)即使尚未完成其工作也会关闭?

1 个答案:

答案 0 :(得分:1)

我想用更好的方法解决这个问题,使用类析构函数本身。我测试了同时运行超过10个ping进程,关闭应用程序杀死了所有这些进程: - )

使用线程来运行进程允许应用程序在运行进程时响应..

    // Example of ShowOutput and ShowError that will be used in Form1.cs
            //void ShowOutput(object sender, DataReceivedEventArgs e)
            //{
            //    if (e.Data != null)
            //        this.InvokeEx(x => x.listBox1.Items.Add(e.Data));
            //}

            //private void ShowError(object sender, DataReceivedEventArgs e)
            //{
            //    if (e.Data != null)
            //        this.InvokeEx(x => x.listBox1.Items.Add(e.Data));
            //}

    namespace WindowsFormsApplication1
    {
        public class CaptureConsole : IDisposable
        {
            private string ExecutableName;
            private string[] Parameters;

            private Process ConsoleProcess = new Process();
            private bool disposed = false; // from MSDN

            private DataReceivedEventHandler OnCaptureOutput;
            private DataReceivedEventHandler OnCaptureError;

            public CaptureConsole() { }

            public CaptureConsole(string _executableName, string[] _parameters, DataReceivedEventHandler _onCaptureOutput, DataReceivedEventHandler _onCaptureError)
            {
                this.ExecutableName = _executableName;
                this.Parameters = _parameters;
                this.OnCaptureOutput = _onCaptureOutput;
                this.OnCaptureError = _onCaptureError;

                ProcessStartInfo startInfo = new ProcessStartInfo()
                {
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    FileName = this.ExecutableName
                };

                // Parsing arguments
                for (int i = 0; i < this.Parameters.Length; i++)
                {
                    if (i == 0)
                        startInfo.Arguments = this.Parameters[0];
                    if (i > 0)
                    {
                        startInfo.Arguments += " ";
                        startInfo.Arguments += this.Parameters[i];
                    }
                }

                Process process = new Process()
                {
                    StartInfo = startInfo
                };
                process.OutputDataReceived += this.OnCaptureOutput;
                process.ErrorDataReceived += this.OnCaptureError;
                process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                process.StartInfo.CreateNoWindow = true;
                process.EnableRaisingEvents = true;
                ConsoleProcess = process;
            }

            public Process Run(int StartDelay = 250)
            {
                Thread processThread = new Thread(() =>
                {
                    ConsoleProcess.Start();
                    ConsoleProcess.BeginOutputReadLine();
                    ConsoleProcess.BeginErrorReadLine();
                }) { IsBackground = true };

                processThread.Start();
                Thread.Sleep(StartDelay);
                return ConsoleProcess;
            }

            //Implement IDisposable.
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
            // from MSDN
            protected virtual void Dispose(bool disposing)
            {
                if (!disposed)
                {
                    if (disposing)
                    {
                        // Manual release of managed resources.
                    }
                    // Release unmanaged resources.
                    try
                    {
                        ConsoleProcess.Kill();
                    }
                    catch { }
                    finally
                    {
                        disposed = true;
                    }
                }
            }

            ~CaptureConsole() { Dispose(false); }
        }
    }

示例使用Form1的代码:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        const string exeName = "ping.exe";
        string[] parameters = new string[] { "127.0.0.1", "-t" };
        Process externalProcess = new Process();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            CaptureConsole RunConsole = new CaptureConsole(exeName, parameters, ShowStdOutput, ShowStdError);
            externalProcess = RunConsole.Run(450);
            this.InvokeEx(x => x.listBox1.Items.Add(String.Format("Process Started: {0}", externalProcess.StartTime)));
        }

        void ShowStdOutput(object sender, DataReceivedEventArgs e)
        {
            try
            {
                if (e.Data != null && !externalProcess.HasExited)
                    this.InvokeEx(x => x.listBox1.Items.Add(e.Data));
            }
            catch { };
        }

        private void ShowStdError(object sender, DataReceivedEventArgs e)
        {
            try
            {
                if (e.Data != null && !externalProcess.HasExited)
                    this.InvokeEx(x => x.listBox1.Items.Add(e.Data));
            }
            catch { };
        }
    }
}