Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirecting standard input/output/error streams with .NET's Process class

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?

like image 206
Stefan Hasler Avatar asked Aug 15 '11 21:08

Stefan Hasler


1 Answers

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");
like image 175
Jalal Said Avatar answered Sep 22 '22 16:09

Jalal Said