我需要生成一个作为控制台应用程序的子进程,并捕获其输出.
我为方法编写了以下代码:
string retMessage = String.Empty; ProcessStartInfo startInfo = new ProcessStartInfo(); Process p = new Process(); startInfo.CreateNoWindow = true; startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardInput = true; startInfo.UseShellExecute = false; startInfo.Arguments = command; startInfo.FileName = exec; p.StartInfo = startInfo; p.Start(); p.OutputDataReceived += new DataReceivedEventHandler ( delegate(object sender, DataReceivedEventArgs e) { using (StreamReader output = p.StandardOutput) { retMessage = output.ReadToEnd(); } } ); p.WaitForExit(); return retMessage;
但是,这不会返回任何内容.我不相信该OutputDataReceived
事件被回调,或者该WaitForExit()
命令可能阻塞该线程,因此它永远不会回调.
有什么建议?
编辑:看起来我在回调中努力了.这样做:
return p.StandardOutput.ReadToEnd();
似乎工作正常.
这是我已经验证可以使用的代码.我用它来产生MSBuild并监听它的输出:
process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.OutputDataReceived += (sender, args) => Console.WriteLine("received output: {0}", args.Data); process.Start(); process.BeginOutputReadLine();
我刚尝试了这件事,以下内容对我有用:
StringBuilder outputBuilder; ProcessStartInfo processStartInfo; Process process; outputBuilder = new StringBuilder(); processStartInfo = new ProcessStartInfo(); processStartInfo.CreateNoWindow = true; processStartInfo.RedirectStandardOutput = true; processStartInfo.RedirectStandardInput = true; processStartInfo.UseShellExecute = false; processStartInfo.Arguments = ""; processStartInfo.FileName = " "; process = new Process(); process.StartInfo = processStartInfo; // enable raising events because Process does not raise events by default process.EnableRaisingEvents = true; // attach the event handler for OutputDataReceived before starting the process process.OutputDataReceived += new DataReceivedEventHandler ( delegate(object sender, DataReceivedEventArgs e) { // append the new data to the data already read-in outputBuilder.Append(e.Data); } ); // start the process // then begin asynchronously reading the output // then wait for the process to exit // then cancel asynchronously reading the output process.Start(); process.BeginOutputReadLine(); process.WaitForExit(); process.CancelOutputRead(); // use the output string output = outputBuilder.ToString();
我需要捕获stdout和stderr并且如果进程在预期时没有退出则超时.我想出了这个:
Process process = new Process(); StringBuilder outputStringBuilder = new StringBuilder(); try { process.StartInfo.FileName = exeFileName; process.StartInfo.WorkingDirectory = args.ExeDirectory; process.StartInfo.Arguments = args; process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellExecute = false; process.EnableRaisingEvents = false; process.OutputDataReceived += (sender, eventArgs) => outputStringBuilder.AppendLine(eventArgs.Data); process.ErrorDataReceived += (sender, eventArgs) => outputStringBuilder.AppendLine(eventArgs.Data); process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); var processExited = process.WaitForExit(PROCESS_TIMEOUT); if (processExited == false) // we timed out... { process.Kill(); throw new Exception("ERROR: Process took too long to finish"); } else if (process.ExitCode != 0) { var output = outputStringBuilder.ToString(); var prefixMessage = ""; throw new Exception("Process exited with non-zero exit code of: " + process.ExitCode + Environment.NewLine + "Output from process: " + outputStringBuilder.ToString()); } } finally { process.Close(); }
我正在将stdout和stderr连接到相同的字符串中,但如果需要,可以将它分开.它使用事件,所以它应该处理它们(我相信).我已成功运行,并将很快进行批量测试.
这里有一些完整而简单的代码.我使用它时工作正常.
var processStartInfo = new ProcessStartInfo { FileName = @"C:\SomeProgram", Arguments = "Arguments", RedirectStandardOutput = true, UseShellExecute = false }; var process = Process.Start(processStartInfo); var output = process.StandardOutput.ReadToEnd(); process.WaitForExit();
请注意,这仅捕获标准输出 ; 它没有捕获标准错误.如果您想要两者,请对每个流使用此技术.
看起来你的两条线路无序.您在设置事件处理程序以捕获输出之前启动该过程.在添加事件处理程序之前,该过程可能刚刚完成.
像这样切换线.
p.OutputDataReceived += ... p.Start();