使用 .NET 的 Process 类重定向标准输入/输出/错误流

发布于 2024-11-29 17:19:51 字数 3834 浏览 1 评论 0原文

我正在尝试为基于交互式控制台的应用程序编写一个包装器。为此,我使用 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++ 编译器编译了虚拟代码,效果相同。

Update2

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

我正在不断尝试。我尝试创建一个 c-Tool,它的功能与我的 c# 工具相同。我使用了 _popen,但效果是,输出显示在进程结束时。嗯,不好。

我找到了 Windows 的替代命令 shell:

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) 使用了一些线程... 但如何解决呢?

I'm trying to write a wrapper for an interactive console-based application. For this I use C# and the Process class. I'm trying to redirect stdin/out/err, but it doesn't work.

Example code:

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();

Nothing happens. But if I start admin.exe and write uptime, output is printed.

All solutions in the internet use ReadToEnd, but I can't use this because i have a dynamic communication on which I have to read stdout/err and write to stdin.

Has anyone an idea?

Update

I played with the posted zip on the linked thread. And then i tried to create a small 'proof-of-concept'-code:

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());
        }
    }
}

It works perfectly:-)

But with the admin.exe it doesn't work? The admin.exe doesn't use any tricky input-method and it doesn't need an inputed password.

I know the admin.exe is written in c and compiled with mingw on linux. So i created a small dummy-tool:

#include <stdio.h>

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

This tool does only echo the inputed text/line. I compiled it with i586-mingw32msvc-gcc and copied it to my windows machine. There i used the program on the top of this post to communicate with the dummy.exe. It doesn't work. No echo is shown. But why?

I compiled the dummy-code also with the Microsoft C++ Compiler, same effect.

Update2

(btw: Thanks to Tim Post)

I'm trying and trying. I tried to create a c-Tool, which does the same as my c# tool. I used _popen, but the effect was, that the output were shown at the end of the process. Hm, not good.

I found this alternative command shell for windows:

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

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

It seems to work. It gets the stdout/err in realtime, can redirect the stdin and admin.exe works. And it is opensource. May be i'll find the solution inside the C++-Code.

I'm not well in C++, so it's hard, but i'll try it. May be i have to write a "clear" redirect-wrapper in C/C++ and use it in C#.

If someone has an idea please say it, because the other way can be very hard (for me^^):-)

Thanks.

best regards

Update 3

Hm, i think this happens because the child-process (admin.exe) uses a few threads...
But how to solve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

指尖上得阳光 2024-12-06 17:19:51

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

此外,您不必使用 Environment.NewLine 来编写字符串,后跟新行,使用 WriteLine 代替,所以:

process.StandardInput.WriteLine("uptime");

The problem could be because of you are using Readline, where the data are output from admin.exe application are sequentially and not in new lines.., try to use Read instead, and build the desirable string from it..

Also you don't have to use Environment.NewLine to write string followed by new line, use WriteLine instead, so:

process.StandardInput.WriteLine("uptime");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文