2012-06-06 81 views
2

我有一個ChildProcessMonitor類,啓動我的過程中,收到的報告數據,並將其退出時重新啓動的過程。我的問題是,一旦進程退出並再次調用啓動,輸出不再報告。爲什麼重新啓動進程時不再接收OutputDataReceived事件?

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

    } 

} 
+0

是輸出停止工作的唯一事件,或者你失去所有的事件(輸出,錯誤,退出)? –

+0

我輸出和錯誤,但退出罰款。 – Kim

+0

您的代碼無法工作,您必須再次調用StartAndMonitor()才能重新啓動該過程。 –

回答

4

嘗試使用:

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; 
    [..] 
} 
+0

啊哈!我現在知道了。這回答我的問題,但我想我會使用@Malcom O'Hares選項2。 – Kim

2

選項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事件每個處理 寫入一行到重定向StandardError的流,直到 過程退出或調用CancelErrorRead時間信號。

MSDN link

所以,你應該只需要做到這一點在你退出處理代碼

_process.Start(); 
    _process.BeginOutputReadLine(); 
    _process.BeginErrorReadLine(); 
+0

不幸的是它不起作用。 – Kim

+0

謝謝。這就是我最終做的事情,但它仍然不能回答我爲什麼事件在原始情況下丟失的問題。 – Kim

+0

感謝您在選項3中的更新,但@DarkGray是正確的,我需要在嘗試再次讀取之前先取消輸出。 – Kim

相關問題