繁体   English   中英

在运行命令提示符.exe应用程序时,将C#WPF应用程序中的特定行定义为超时

[英]Define timeout to specific line in C# WPF application while running command prompt .exe application

在我的主要WPF应用程序代码中,我需要使用命令提示符运行.exe应用程序。 这个动作是在backgroundworker内部执行的,我有以下代码。 代码正在运行带有命令提示符的readlines.exe应用程序,并将输出行读入字符串(str)。

string str;
ProcessStartInfo proc = new ProcessStartInfo();
proc.WindowStyle = ProcessWindowStyle.Hidden;
proc.UseShellExecute = true;
proc.FileName = @"readlines.exe";
proc.Arguments = @"";
proc.UseShellExecute = false;
proc.RedirectStandardOutput = true;
proc.CreateNoWindow = true;
proc.RedirectStandardInput = true;

Process proc1 = Process.Start(proc);
proc1.StandardInput.WriteLine("");

str = proc1.StandardOutput.ReadToEnd();

我想将超时广告添加到下一行,以便在确定超时时取消处理(如CTR + C),并且“ str”将获取输出文本,直到这一点为止。

str = proc1.StandardOutput.ReadToEnd();

可能吗?

尽管先前的答案已经被接受,但是这里的解决方案可能更有用,更安全且性能更高。 此外,它不使用ReadLine()方法,该方法将阻塞直到写入一行(这可能永远不会发生)。 它使用StringBuilder的实例,并以指定的数据块(默认大小为128个字符)从流中读取数据。 此外,它支持基于事件的读取数据通知。

该类的用法保持不变。

ProcessOutputReader por = new ProcessOutputReader(proc1);
por.StartReading();

// Do whatever you want here
// (e.g. sleep or whatever)

por.StopReading();

// Now you have everything that has been read in por.Data

但是,我添加了OnDataRead事件,该事件在每次读取新数据时都会触发。 您可以使用以下代码访问数据:

...
// Subscribe to the event
por.OnDataRead += OnDataReadEventHandler;
...

回调方法/事件处理程序如下所示:

private void OnDataReadEventHandler(object sender, ProcessOutputReaderEventArgs e)
{
    // e.IntermediateDataStore points to the StringBuilder instance which holds
    // all the data that has been received until now.
    string completeData = e.IntermediateDataStore.ToString();

    // e.NewData points to a string which contains the data that has been received
    // since the last triggered event (because the event is triggered on each read).
    string newData = e.NewData;
}

修改后的ProcessOutputReader类如下所示:

/// <summary>
/// Represents the ProcessOutputReader class.
/// </summary>
public class ProcessOutputReader
{
    /// <summary>
    /// Represents the instance of the thread arguments class.
    /// </summary>
    private ProcessOutputReaderWorkerThreadArguments threadArguments;

    /// <summary>
    /// Initializes a new instance of the <see cref="ProcessOutputReader"/> class.
    /// </summary>
    /// <param name="process">The process which's output shall be read.</param>
    /// <exception cref="System.ArgumentOutOfRangeException">Is thrown if the specified process reference is null.</exception>
    public ProcessOutputReader(Process process)
    {
        if (process == null)
        {
            throw new ArgumentOutOfRangeException("process", "The parameter \"process\" must not be null");
        }

        this.Process = process;
        this.IntermediateDataStore = new StringBuilder();
        this.threadArguments = new ProcessOutputReaderWorkerThreadArguments(this.Process, this.IntermediateDataStore);
    }

    /// <summary>
    /// Is fired whenever data has been read from the process output.
    /// </summary>
    public event EventHandler<ProcessOutputReaderEventArgs> OnDataRead;

    /// <summary>
    /// Gets or sets the worker thread.
    /// </summary>
    private Thread ReaderThread
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the intermediate data store.
    /// </summary>
    private StringBuilder IntermediateDataStore
    {
        get;
        set;
    }

    /// <summary>
    /// Gets the data collected from the process output.
    /// </summary>
    public string Data
    {
        get
        {
            return this.IntermediateDataStore.ToString();
        }
    }

    /// <summary>
    /// Gets the process.
    /// </summary>
    public Process Process
    {
        get;
        private set;
    }

    /// <summary>
    /// Stars reading from the process output.
    /// </summary>
    public void StartReading()
    {
        if (this.ReaderThread != null)
        {
            if (this.ReaderThread.IsAlive)
            {
                return;
            }
        }

        this.ReaderThread = new Thread(new ParameterizedThreadStart(ReaderWorker));
        this.threadArguments.Exit = false;
        this.ReaderThread.Start(this.threadArguments);
    }

    /// <summary>
    /// Stops reading from the process output.
    /// </summary>
    public void StopReading()
    {
        if (this.ReaderThread != null)
        {
            if (this.ReaderThread.IsAlive)
            {
                this.threadArguments.Exit = true;
                this.ReaderThread.Join();
            }
        }
    }

    /// <summary>
    /// Fires the OnDataRead event.
    /// </summary>
    /// <param name="newData">The new data that has been read.</param>
    protected void FireOnDataRead(string newData)
    {
        if (this.OnDataRead != null)
        {
            this.OnDataRead(this, new ProcessOutputReaderEventArgs(this.IntermediateDataStore, newData));
        }
    }

    /// <summary>
    /// Represents the worker method.
    /// </summary>
    /// <param name="data">The thread arguments, must be an instance of the <see cref="ProcessOutputReaderWorkerThreadArguments"/> class.</param>
    private void ReaderWorker(object data)
    {
        ProcessOutputReaderWorkerThreadArguments args;

        try
        {
            args = (ProcessOutputReaderWorkerThreadArguments)data;
        }
        catch
        {
            return;
        }

        try
        {
            char[] readBuffer = new char[args.ReadBufferSize];

            while (!args.Exit)
            {
                if (args.Process == null)
                {
                    return;
                }

                if (args.Process.HasExited)
                {
                    return;
                }

                if (args.Process.StandardOutput.EndOfStream)
                {
                    return;
                }

                int readBytes = this.Process.StandardOutput.Read(readBuffer, 0, readBuffer.Length);
                args.IntermediateDataStore.Append(readBuffer, 0, readBytes);

                this.FireOnDataRead(new String(readBuffer, 0, readBytes));
            }
        }
        catch (ThreadAbortException)
        {
            if (!args.Process.HasExited)
            {
                args.Process.Kill();
            }
        }
    }
}

另外,您需要如下所示的ProcessOutputReaderWorkerThreadArguments类:

/// <summary>
/// Represents the ProcessOutputReaderWorkerThreadArguments class.
/// </summary>
public class ProcessOutputReaderWorkerThreadArguments
{
    /// <summary>
    /// Represents the read buffer size,
    /// </summary>
    private int readBufferSize;

    /// <summary>
    /// Initializes a new instance of the <see cref="ProcessOutputReaderWorkerThreadArguments"/> class.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="intermediateDataStore">The intermediate data store.</param>
    public ProcessOutputReaderWorkerThreadArguments(Process process, StringBuilder intermediateDataStore)
    {
        this.ReadBufferSize = 128;
        this.Exit = false;
        this.Process = process;
        this.IntermediateDataStore = intermediateDataStore;
    }

    /// <summary>
    /// Gets or sets a value indicating whether the thread shall exit or not.
    /// </summary>
    public bool Exit
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the read buffer size in bytes.
    /// </summary>
    /// <exception cref="System.ArgumentOutOfRangeException">Is thrown if the specified value is not greather than 0.</exception>
    public int ReadBufferSize
    {
        get
        {
            return this.readBufferSize;
        }
        set
        {
            if (value <= 0)
            {
                throw new ArgumentOutOfRangeException("value", "The specified value for \"ReadBufferSize\" must be greater than 0.");
            }

            this.readBufferSize = value;
        }
    }

    /// <summary>
    /// Gets the process.
    /// </summary>
    public Process Process
    {
        get;
        private set;
    }

    /// <summary>
    /// Gets the intermediate data store.
    /// </summary>
    public StringBuilder IntermediateDataStore
    {
        get;
        private set;
    }
}

还有ProcessOutputReaderEventArgs类,如下所示:

/// <summary>
/// Represents the ProcessOutputReaderEventArgs class.
/// </summary>
public class ProcessOutputReaderEventArgs : EventArgs 
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ProcessOutputReaderEventArgs"/> class.
    /// </summary>
    /// <param name="intermediateDataStore">The reference to the intermediate data store.</param>
    /// <param name="newData">The new data that has been read.</param>
    public ProcessOutputReaderEventArgs(StringBuilder intermediateDataStore, string newData)
    {
        this.IntermediateDataStore = intermediateDataStore;
        this.NewData = newData;
    }

    /// <summary>
    /// Gets the reference to the intermediate data store.
    /// </summary>
    public StringBuilder IntermediateDataStore
    {
        get;
        private set;
    }

    /// <summary>
    /// Gets the new data that has been read.
    /// </summary>
    public string NewData
    {
        get;
        private set;
    }
}

如何实现此目的的一些示例( 注意,未经测试的代码可以改进

ProcessOutputReader por = new ProcessOutputReader(proc1);
por.StartReading();

// Do whatever you want here
// (e.g. sleep or whatever)

por.StopReading();

// Now you have everything that has been read in por.Lines

该类如下所示:

public class ProcessOutputReader
{
    public ProcessOutputReader(Process process)
    {
        this.Process = process;
        this.Lines = new List<string>();
    }

    public List<string> Lines
    {
        get;
        private set;
    }

    public Process Process
    {
        get;
        private set;
    }

    private Thread ReaderThread
    {
        get;
        set;
    }

    public void StartReading()
    {
        if (this.ReaderThread == null)
        {
            this.ReaderThread = new Thread(new ThreadStart(ReaderWorker));
        }

        if (!this.ReaderThread.IsAlive)
        {
            this.ReaderThread.Start();
        }
    }

    public void StopReading()
    {
        if (this.ReaderThread != null)
        {
            if (this.ReaderThread.IsAlive)
            {
                this.ReaderThread.Abort();
                this.ReaderThread.Join();
            }
        }
    }

    private void ReaderWorker()
    {
        try
        {
            while (!this.Process.HasExited)
            {
                string data = this.Process.StandardOutput.ReadLine();
                this.Lines.Add(data);
            }
        }
        catch (ThreadAbortException)
        {
            if (!this.Process.HasExited)
            {
                this.Process.Kill();
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM