2

我正在通过 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 上输出数据),然后陷入无限循环。(这是可接受的行为)。

这两种情况都已使用 cmd 进行了验证。

有关新尝试的详细信息

我编写了 ac# 应用程序(称为虚拟应用程序),它模仿了本机应用程序的行为,并且这段代码运行良好。但是,当为本机应用程序运行时,我什么也得不到。

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

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

我还尝试更改本机应用程序的换行符。由于它是用 c 语言实现的,所以它使用 \n 作为换行符。我尝试使用两个 \r\n 对换行,但 StdOut 仍然是空白的(对于案例 2)。

4

1 回答 1

0

我有同样的审讯和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可以使用相同的模式

请注意,可能会错过子进程的一些未刷新的输出,但是在我的情况下,我对需要被杀死的进程的期望不高,最多是一些用于调试目的的信息。

于 2017-11-30T15:52:22.353 回答