使用 .NET 的 Process 类重定向标准输入/输出/错误流
我正在尝试为基于交互式控制台的应用程序编写一个包装器。为此,我使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题可能是因为您使用的是
Readline
,其中从admin.exe
应用程序输出的数据是按顺序输出的,而不是换行。 .,尝试使用Read
代替,并从中构建所需的字符串。此外,您不必使用
Environment.NewLine
来编写字符串,后跟新行,使用WriteLine
代替,所以:The problem could be because of you are using
Readline
, where the data are output fromadmin.exe
application are sequentially and not in new lines.., try to useRead
instead, and build the desirable string from it..Also you don't have to use
Environment.NewLine
to write string followed by new line, useWriteLine
instead, so: