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

16,415

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");
Share:
16,415
Stefan Hasler
Author by

Stefan Hasler

Updated on June 04, 2022

Comments

  • Stefan Hasler
    Stefan Hasler almost 2 years

    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?

  • user1703401
    user1703401 over 12 years
    There is no ReadLine() in the snippet.
  • Jalal Said
    Jalal Said over 12 years
    Yes, I was referring to BeginOutputReadLine and so the e.Data in OutputDataReceived will just read lines, I think the same also apply to BeginErrorReadLine here..
  • Kiquenet
    Kiquenet over 9 years
    You need to set UseShellExecute to true for the Verb to be respected and it must be set to 'false' to redirect standard output. You can't do both. I'm pretty sure Windows also won't allow you to redirect standard input/output/error across the admin/non-admin security boundary. You'll have to find a different way to get output from the program running as admin - Reference: stackoverflow.com/a/8690661