Redirecting standard input / output / error streams using the .NET Process class

I am trying to write a shell for an interactive console application. For this, I use the C # and Process classes. I am trying to redirect stdin / out / err , but it does not work.

Code example:

 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 , the output is printed.

All solutions on the Internet use ReadToEnd , but I canโ€™t use it because I have a dynamic link on which I have to read stdout / err and write to stdin .

Does anyone have an idea?

Update

I played with a published zip code in a related topic. And then I tried to create a little "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 great :-)

But admin.exe it not work with admin.exe ? admin.exe does not use any complicated input method and does not need the password entered.

I know admin.exe written in c and compiled from mingw on linux. So, I created a small mannequin tool:

 #include <stdio.h> int main() { int readed; while ((readed = fgetc(stdin)) >= 0) fputc((char)readed, stdout); } 

This tool only echoes the input of the entered text / line. I compiled it using i586-mingw32msvc-gcc and copied it to my windows machine. There I used the program at the top of this post to communicate with dummy.exe . This does not work. Echo is not displayed. But why?

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

Update2

(btw: Thanks Tim Post)

I try and try. I tried to create a c-Tool that does the same thing as my C # tool. I used _popen , but the effect was that the output was shown at the end of the process. Hmm, not good.

I found this alternate command shell for windows:

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

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

It seems to have worked. It gets stdout / err in real time, can redirect stdin and admin.exe works. And it is open source. Perhaps I will find a solution inside C ++ code.

I feel bad in C ++, so it's hard, but I will try. Maybe I need to write a โ€œclearโ€ overriding shell in C / C ++ and use it in C #.

If anyone has an idea, tell me about it, because the other way can be very difficult (for me ^^) :-)

Thanks.

Best wishes

Update 3

Hm, I think this is because the child process ( admin.exe ) uses multiple threads ... But how to solve it?

+6
source share
1 answer

The problem may be that you are using Readline , where the data is output from the admin.exe application, sequentially and not in new lines .. try using Read instead and create the desired line from it ..

You also do not need to use Environment.NewLine to write a line followed by a new line, use WriteLine instead, so:

 process.StandardInput.WriteLine("uptime"); 
+1
source

Source: https://habr.com/ru/post/895093/


All Articles