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

时间:2014-06-08 09:31:38

标签: c# .net wpf software-design

在我的主要WPF应用程序代码中,我需要使用命令提示符运行.exe app。这个动作在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();

我希望广告超时到以下行,所以当超时结束时,procces将被取消(如CTR + C)和" str"将得到输出文本,直到这一点。

str = proc1.StandardOutput.ReadToEnd();

有可能吗?

2 个答案:

答案 0 :(得分:1)

虽然之前的答案已被接受,但这可能是一个更有用,更安全,更高效的解决方案。此外,它没有使用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;
    }
}

答案 1 :(得分:0)

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

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