【问题标题】:Redirecting standard input/output/error streams with .NET's Process class使用 .NET 的 Process 类重定向标准输入/输出/错误流
【发布时间】:2011-10-27 14:51:34
【问题描述】:

我正在尝试为基于控制台的交互式应用程序编写包装器。为此,我使用 C# 和 Process 类。我正在尝试重定向stdin/out/err,但它不起作用。

示例代码:

ProcessStartInfo startInfo = new ProcessStartInfo("admin.exe");
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;

Process process = Process.Start(startInfo);
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);

while (true)
{
    process.StandardInput.Write("uptime" + Environment.NewLine);
    process.StandardInput.Flush();
    Thread.Sleep(1000);
}
Console.ReadKey();

什么都没有发生。但是如果我开始admin.exe 并写uptime,就会打印输出。

互联网上的所有解决方案都使用ReadToEnd,但我不能使用它,因为我有一个动态通信,我必须阅读stdout/err并写信给stdin

有人有想法吗?

更新

我玩过链接线程上发布的 zip。然后我尝试创建一个小的“概念验证”代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading; 

namespace ConsoleApplication3
{
    class Program
    {
        private static void Read(StreamReader reader)
        {
            new Thread(() =>
                {
                    while (true)
                    {
                        int current;
                        while ((current = reader.Read()) >= 0)
                            Console.Write((char)current);
                    }
                }).Start();
        }

        static void Main(string[] args)
        {
            ProcessStartInfo startInfo = new ProcessStartInfo(@"cmd.exe");
            startInfo.CreateNoWindow = true;
            startInfo.ErrorDialog = false;
            startInfo.RedirectStandardError = true;
            startInfo.RedirectStandardInput = true;
            startInfo.RedirectStandardOutput = true;
            startInfo.UseShellExecute = false;
            startInfo.CreateNoWindow = true;
            Process process = new Process();
            process.StartInfo = startInfo;
            process.Start();
            Read(process.StandardOutput);
            Read(process.StandardError);
            while (true)
                process.StandardInput.WriteLine(Console.ReadLine());
        }
    }
}

完美运行:-)

但是admin.exe 不行吗? admin.exe 不使用任何棘手的输入法,也不需要输入密码。

我知道admin.exe 是用c 编写的,并在Linux 上用mingw 编译。所以我创建了一个小虚拟工具:

#include <stdio.h>

int main() {
        int readed;
        while ((readed = fgetc(stdin)) >= 0)
                fputc((char)readed, stdout);
}

此工具仅回显输入的文本/行。我用i586-mingw32msvc-gcc 编译它并将它复制到我的Windows 机器上。在那里,我使用了这篇文章顶部的程序与dummy.exe 进行通信。它不起作用。没有显示回声。但为什么呢?

我也用 Microsoft C++ Compiler 编译了虚拟代码,效果相同。

更新2

(顺便说一句:感谢 Tim Post)

我一直在尝试。我试图创建一个 c-Tool,它和我的 c# 工具一样。我使用了_popen,但效果是,输出显示在进程结束时。嗯,不好。

我找到了这个 Windows 的替代命令外壳:

https://stackoverflow.com/questions/440269/whats-a-good-alternative-windows-console

http://sourceforge.net/projects/console/

它似乎工作。它实时获取标准输出/错误,可以重定向标准输入和admin.exe 工作。它是开源的。也许我会在 C++ 代码中找到解决方案。

我的 C++ 不好,所以很难,但我会试试的。可能我必须在 C/C++ 中编写一个“清晰”的重定向包装器并在 C# 中使用它。

如果有人有想法请说出来,因为另一种方式可能很难(对我来说^^):-)

谢谢。

最好的问候

更新 3

嗯,我认为这是因为子进程 (admin.exe) 使用了几个线程... 但是如何解决呢?

【问题讨论】:

  • 我遇到了完全相同的问题,并提出了一个(有点笨拙的)解决方案,您可以在这里找到:stackoverflow.com/questions/6655613/…。我相信这也有一个指向 .ZIP 的链接以及完整的解决方案。
  • 有些程序只是对输入/输出重定向很感兴趣。 Admin.exe 是一个强大的提示,它会想要从真正的控制台读取密码。
  • 我已合并您未注册的帐户并将您的答案转换为对您问题的编辑,请检查准确性。您现在应该可以完全控制自己的问题和答案了。
  • 您可能对this post 感兴趣,它涵盖了使用 .NET 进程的许多复杂性,尤其是在处理输入和输出方面。它推荐MedallionShell库,它简化了处理进程io流
  • 如果一次读取一个字符会怎样? ReadLine 需要按回车键。 while (true) { p.StandardInput.Write(Console.ReadKey()); }

标签: c# process stdout stdin stderr


【解决方案1】:

问题可能是因为您使用的是Readline,其中从admin.exe 应用程序输出的数据是按顺序输出的,而不是换行......,请尝试改用Read ,并从中构建所需的字符串..

另外,您不必使用Environment.NewLine 来编写字符串后跟换行符,而是使用WriteLine,所以:

process.StandardInput.WriteLine("uptime");

【讨论】:

  • sn-p 中没有 ReadLine()。
  • 是的,我指的是BeginOutputReadLine,所以OutputDataReceived 中的e.Data 只会读取行,我认为这同样适用于BeginErrorReadLine 这里..
  • 您需要将 UseShellExecute 设置为 true 才能尊重动词,并且必须将其设置为“false”以重定向标准输出。你不能两者都做。我很确定 Windows 也不允许您跨管理员/非管理员安全边界重定向标准输入/输出/错误。您必须找到一种不同的方法来从以管理员身份运行的程序中获取输出 - 参考:stackoverflow.com/a/8690661
猜你喜欢
  • 1970-01-01
  • 2022-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-02
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多