2

プロセスを起動し、受信したデータを報告し、プロセスが終了するとプロセスを再開するChildProcessMonitorクラスがあります。私の問題は、プロセスが終了してStartが再度呼び出されると、出力が報告されなくなることです。

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace WcfClient
{
    /// <summary>
    /// Can be used to launch and monitor (restart on crash) the child process.
    /// </summary>
    public class ChildProcessMonitor
    {
        private Process _process;

        /// <summary>
        /// Starts and monitors the child process.
        /// </summary>
        /// <param name="fullProcessPath">The full executable process path.</param>
        public void StartAndMonitor(string fullProcessPath)
        {
            StartAndMonitor(fullProcessPath, null);
        }

        /// <summary>
        /// Starts and monitors the child process.
        /// </summary>
        /// <param name="fullProcessPath">The full executable process path.</param>
        /// <param name="arguments">The process arguments.</param>
        public void StartAndMonitor(string fullProcessPath, string arguments)
        {
            ProcessStartInfo processStartInfo = new ProcessStartInfo
            {
                CreateNoWindow = true,
                FileName = fullProcessPath,
                WorkingDirectory = Path.GetDirectoryName(fullProcessPath) ?? string.Empty,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true
            };

            processStartInfo.Arguments = arguments;             

            _process = new Process { StartInfo = processStartInfo, EnableRaisingEvents = true };
            _process.OutputDataReceived += OnOutputDataReceived;
            _process.ErrorDataReceived += OnErrorDataReceived;
            _process.Start();
            _process.BeginOutputReadLine();
            _process.BeginErrorReadLine();
            _process.Exited += OnProcessExited;
        }

        /// <summary>
        /// Called when process exits.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnProcessExited(object sender, EventArgs e)
        {
            if (_process != null)
            {
                Thread.Sleep(2000);                 
                _process.Start();                       
            }
        }

        /// <summary>
        /// The ErrorDataReceived event indicates that the associated process has written to its redirected StandardError stream.
        /// </summary>
        public DataReceivedEventHandler ErrorDataReceived;

        /// <summary>
        /// Called when error data received.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Diagnostics.DataReceivedEventArgs"/> instance containing the event data.</param>
        private void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            Trace.WriteLine("Error data.");
            if (ErrorDataReceived != null)
            {
                ErrorDataReceived(sender, e);
            }
        }

        /// <summary>
        /// The OutputDataReceived event indicates that the associated Process has written to its redirected StandardOutput stream.
        /// </summary>
        public DataReceivedEventHandler OutputDataReceived;

        /// <summary>
        /// Called when output data received.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Diagnostics.DataReceivedEventArgs"/> instance containing the event data.</param>
        private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            Trace.WriteLine("Output data.");
            if (OutputDataReceived != null)
            {
                OutputDataReceived(sender, e);
            }
        }

    }

}
4

2 に答える 2

5

使用してみてください:

private void OnProcessExited(object sender, EventArgs e)
{
  if (_process != null)
  {
    Thread.Sleep(2000);
    _process.CancelOutputRead();
    _process.CancelErrorRead();
    _process.Start();
    _process.BeginOutputReadLine();
    _process.BeginErrorReadLine();

  }
}

ps

簡単な説明:OutputReadとErrorReadが閉じられ、プロセスが再起動しました。

リフレクションからのコードを含む長い説明:

public void BeginOutputRead()
{
  [..]
  if (this.output == null)
  {
    [..]                    
    this.output = new AsyncStreamReader(this, baseStream, new UserCallBack(this.OutputReadNotifyUser), this.standardOutput.CurrentEncoding);
  }
}

public void Start()
{   
    this.Close();
    [..]
}

public void Close()
{   
    [..]
    this.output = null;
    this.error = null;
    [..]
}
于 2012-06-06T20:06:05.640 に答える
3

オプション1-機能しなかった

この編集を試してみます。オブジェクトのイベントハンドラーが更新されます。

private void OnProcessExited(object sender, EventArgs e)
        {
            if (_process != null)
            {
                Thread.Sleep(2000); 
                _process.OutputDataReceived -= OnOutputDataReceived;
                _process.ErrorDataReceived -= OnErrorDataReceived;
                _process.OutputDataReceived += OnOutputDataReceived;
                _process.ErrorDataReceived += OnErrorDataReceived;                
                _process.Start();                       
            }
        }

オプション2

私の次のアイデアは、わずかな設計変更を提案することです。ProcessStartInfoをクラスに保存し、既存のプロセスでStartを呼び出す代わりに終了が発生した場合は、それを破棄し、ProcessStartInfoオブジェクトを使用して新しいプロセスを作成します。

オプション3

プロセスクラスのMSDNを読んだ後、この抜粋で問題が説明されていると思います

ErrorDataReceivedイベントは、関連付けられたプロセスがリダイレクトされたStandardErrorストリームに書き込まれたことを示します。

このイベントは、StandardErrorの非同期読み取り操作中にのみ発生します。非同期読み取り操作を開始するには、プロセスのStandardErrorストリームをリダイレクトし、イベントハンドラーをErrorDataReceivedイベントに追加して、BeginErrorReadLineを呼び出す必要があります。その後、ErrorDataReceivedイベントは、プロセスが終了するか、CancelErrorReadを呼び出すまで、プロセスがリダイレクトされたStandardErrorストリームに行を書き込むたびに通知します。

MSDNリンク

したがって、出口処理コードでこれを行う必要があります

    _process.Start();
    _process.BeginOutputReadLine();
    _process.BeginErrorReadLine();
于 2012-06-06T18:26:37.703 に答える