2015-10-29 20 views
1

我正在制作一个应用程序,它将产生一个具有命令行解释器的进程。我需要从另一台机器向这个CLI提供命令。现在,我必须检测命令何时完成,因此我正在检查CLI提示何时出现在我产生的进程的标准输出中。这里有一段代码:为什么OutputDataReceived不会为提示而引发,从而阻止AutoResetEvent发出信号?

private string StartProcess(string input) 
{ 
try 
{ 
    StringBuilder output = new StringBuilder(); 
    StringBuilder error = new StringBuilder(); 

    AutoResetEvent commandFinished = new AutoResetEvent(false); 

    ProcessStartInfo startInfo = new ProcessStartInfo() 
    { 
     FileName = "myprocess.exe", 
     Arguments = "", 
     UseShellExecute = false, 
     CreateNoWindow = true, 
     RedirectStandardOutput = true, 
     RedirectStandardError = true, 
     RedirectStandardInput = true, 
     UserName = System.Environment.UserName 
    }; 

    Process myProcess = new Process() 
    { 
     StartInfo = startInfo, 
     EnableRaisingEvents = true 
    }; 

    myProcess.OutputDataReceived += new DataReceivedEventHandler((sender, e) => 
    { 
     if (e.Data != null) 
     { 
      string prompt = "user >"; 

      if (e.Data.Substring(e.Data.Length - prompt.Length).Equals(prompt)) 
      { 
       Console.WriteLine("Received prompt! Sending CommandFinished signal!"); 
       commandFinished.Set(); 
       Console.WriteLine("CommandFinished signal set!"); 
      } 
      else 
      { 
       output.AppendLine(e.Data); 
      } 
     } 
     else 
     { 
      // Data finished 
      Console.WriteLine("StdOut data finished! Sending CommandFinished signal!"); 
      commandFinished.Set(); 
      Console.WriteLine("CommandFinished signal set!"); 
     } 
    }); 


    myProcess.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => 
    { 
     if (e.Data != null) 
     { 
      Console.WriteLine("Error Data received: " + e.Data.ToString()); 
      error.AppendLine(e.Data); 
     } 
    }); 

    myProcess.Start(); 
    myProcess.BeginOutputReadLine(); 
    myProcess.BeginErrorReadLine(); 

    Console.WriteLine("Executing input command: " + input); 
    myProcess.StandardInput.WriteLine(input); 

    Console.WriteLine("Waiting for input command to complete..."); 

    commandFinished.WaitOne(); 

    Console.WriteLine("Command complete!"); 

    return output.ToString(); 
} 
catch (Exception ex) 
{ 
    Console.WriteLine("EXCEPTION: " + ex.ToString()); 
    throw ex; 
} 
} 

现在,代码挂在对WaitOne()的调用上。我很困惑,为什么 - 我没有在输出中检测到CLI提示符,并且我从来没有得到任何WriteLines告诉我在OutputDataReceived事件中收到提示,或收到的数据为空。即当前一个命令完成并且显示提示时,OutputDataReceived事件不会引发。

我提供的输入命令确实需要一段时间,但确实完成了。我在这里使用AutoResetEvent错误吗?

+0

您是否确认通风管理器正在被调用?如果我不得不猜测,我敢打赌问题是输出数据末尾还有其他内容,比如空格,或者提示符被分割为多个DataReceived事件(可能是“用户”和一个对于“>”)。 –

+0

您还需要处理'e.Data.Length - prompt.Length'小于0 –

+0

@DarkFalcon,我实际上捕获输出,如果我没有得到提示,所以我应该看到提示(或部分如果是这样的话,我只能看到输出的前几行,然后挂起。 – Tino

回答

2

如果没有a good, minimal, complete code example无法确切知道代码可能存在什么问题。但是我可以看到一个明显的解释:

OutputDataReceived事件发生在每个收到的输出。也就是说,一个以换行符结尾的字符串。

没有关于您的外部过程的细节,我不能肯定地说。但是大多数CLI类型的情况涉及显示而没有换行符。即提示将被写入控制台,并且用户输入预计会在提示符后立即响应到控制台,而不是在下一行。

如果您的情况属于这种情况,那么您几乎可以肯定无法检测到提示,因为事件不会针对提示单独提出。在上一个命令操作的最后一行输出之后,下一次事件将在之后通过标准输入发送到进程。这对于知道何时发送该命令来说显然太晚了。 :)

为了得到这个工作,你必须通过而不是基于行的其他机制之一读取过程中的输入。

+0

事实上,OutputDataReceived事件只会在行上产生,这是个问题。谢谢! – Tino

相关问题