views:

403

answers:

4

I'm trying to put together a wrapper around a console application using StandardInput and StandardOutput. I'm getting stuck where the console application would prompt for input such as a password.

I'd like to read from StandardOutput, prompt the user using the read text, and write the user's input back to the console application using its StandardInput. Seems easy enough, here's what I have currently:

        Process process = new Process()
        {
            StartInfo =
            {
                FileName = "bin\\vpnc.exe",
                Arguments = "--no-detach --debug 0",
                CreateNoWindow = true,
                UseShellExecute = false,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
            }
        };

        process.OutputDataReceived += (s, args) => 
        {
            textBlock1.Dispatcher.Invoke(new Action(() =>
            {
                textBlock1.Text += args.Data;
            }));
        };
        process.Start();
        process.BeginOutputReadLine();

The problem is that BeginOutputReadLine() is doing just that...waiting for a line ending. In this case it just sits, and sits, and sits because there is no line to read...the console application has written out text with no line ending and is waiting for input. Coincidentally, when I manually kill the process the event fires and I get the text.

Is there a way to tell that the process is waiting for StandardInput? Or am I missing a completely obvious way to accomplish the goal?

+1  A: 

process.StandardOutput.BaseStream.BeginRead(...) is a potential substitute for your readline, and that will not wait for a line ending however you'd need to know what terminates the output to figure out when not to start wait for the next chunk of data

Rune FS
Would that be StandardOutput.BaseStream.BeginRead(...)? I don't see that method on StandardOutput, which is a StreamReader. Would reading directly from StandardOutput.BaseStream screw with the reader?
John Clayton
@John my bad sorry yes that would be BaseStream.BeginRead
Rune FS
+1  A: 

Unless you need something asynchronous you probably want ReadToEnd.

Here is a list of all StreamReader Methods

Greg Bahrey
ReadToEnd also hangs when the console is waiting for input.
John Clayton
ReadToEnd is usually only adviceable together with WaitForExit cuz you might not have an end before that. The problem is though that you migt end up with a app that do not exit before the stream has been read making ReadToEnd and WaitForExit a potential deadlock
Rune FS
A: 

Hi

As Rune said, you can access directly to the output stream of the process (process.StandardOutput) and read from there (if you don't want to wait until a line break is entered into the console app), but this means that you need to check periodically for new data.

To interact with the application, you can just write to the StandardInput of the process (create a StreamWriter that writes to the process.StandardInput).

A nice sample of writing to it is on the MSDN documentation (http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspx).

Hope this helps

willvv
A: 

You need to use the synchronous read method and handle any necessary threading yourself. The below code won't tell you that input is expected, but you will be able to detect that a prompt is displayed.

        char[] b = new char[1024];
        while (!process.HasExited) {
            int c = process.StandardOutput.Read(b, 0, b.Length);
            context.Response.Write(b, 0, c);
            Thread.Sleep(100);
        }
Tom Clarkson