使用Process.kill异常终止进程后读取StdOut

时间:2013-11-02 12:45:25

标签: c# process stdout

我通过c#Diagnostics.Process类调用exe并从它的StdOut读取输出。如果它在指定的时间内没有自动终止,则强制终止该过程,例如:

process.StartInfo.FileName = @"D:\t.exe";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;

process.WaitForExit(500);

if (!process.HasExited)
{
    process.Kill();
    process.WaitForExit();
}
string stdOutContents = process.StandardOutput.ReadToEnd();

现在问题是当exe正常终止时,代码会成功运行。但是如果它无法正常终止(通常exe会陷入某个无限循环),stdOutContents将被读作空字符串。

如何在进程被终止后读取StdOut(不使用process.OutputDataReceived事件技术)? (已经证实,exe-in-question确实会将某些内容写入StdOut,即使它被卡在某处)。


更新1

有关正在调用的Exe的详细信息(在此问题中称为“本机应用”)

它是一个用c语言实现的小工具,使用MS C ++编译器编译。它在将状态信息输出到StdOut(使用putchar)时完成其工作。

只有两种可能的操作情况:

  1. 它会成功运行,同时将一些数据打印到StdOut上。
  2. 它将正常运行到某一点(同时在StdOut上输出数据)然后陷入无限循环。 (这是可接受的行为)。
  3. 已使用cmd验证了这两种方案。

    有关新尝试的详细信息

    我写了一个c#app(称为虚拟应用程序),模仿本机应用程序行为,这段代码工作正常。但是,当为本机应用程序运行时,我什么都得不到。

    我不明白为什么代码无法读取原生应用程序输出的内容?

    我也尝试使用OutputDataReceived的事件处理程序。当代码试图终止进程时,它只被args.Data = null调用一次。检查虚拟应用程序的行为表明,当调用process.kill时,将使用args.Data = null调用该处理程序。因此,这似乎是两种应用程序的标准行为。

    我也尝试更改原生应用的换行符。由于它是用c语言实现的,因此它使用\ n作为换行符。我尝试将\ r \ n对用于换行,但StdOut仍为空白(对于案例2)。

1 个答案:

答案 0 :(得分:0)

我有同样的讯问而doc of Process.Kill

  

如果您致电Kill,则由流程编辑的数据或分配给流程的资源可能会丢失。

这似乎表明您不能依赖于读取进程的StandardOutput,尽管没有明确说明输出/错误流已被处理。

我终于受到了这个答案的启发 How to spawn a process and capture its STDOUT in .NET?

我使用以下代码:

var info = new ProcessStartInfo("some.exe");
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;

using (var p = new Process())
{
    p.StartInfo = info;
    var output = new StringBuilder();
    p.OutputDataReceived += (sender, eventArgs) =>
    {
        output.AppendLine(eventArgs.Data);
    };
    p.Start();
    p.BeginOutputReadLine();
    if (!p.WaitForExit(5000))
    {
        Console.WriteLine("Taking too long...");
        p.Kill();
        Console.WriteLine("Process killed, output :\n" + output);
    }
}

相同的模式可以与 ErrorDataReceived

一起使用

请注意,可能会错过子进程的某些未刷新的输出,但是在我的情况下,我不希望从需要被杀死的进程中获取太多内容,最多用于调试目的的一些信息。