How to use an interactive command-line program from another .NET program

I need to write a shell for an interactive command line.

This means that I need to be able to send commands to another program through standard input and receive a response through standard output.

The problem is that the standard output stream seems to be blocked while the input stream is still open. As soon as I close the input stream, I get a response. But then I can not send more teams.

This is what I'm using at the moment (mostly from here ):

void Main() {
    Process process;
    process = new Process();
    process.StartInfo.FileName = "atprogram.exe";
    process.StartInfo.Arguments = "interactive";

    // Set UseShellExecute to false for redirection.
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;

    // Redirect the standard output of the command.  
    // This stream is read asynchronously using an event handler.
    process.StartInfo.RedirectStandardOutput = true;
    // Set our event handler to asynchronously read the output.
    process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);

    // Redirect standard input as well. This stream is used synchronously.
    process.StartInfo.RedirectStandardInput = true;
    process.Start();

    // Start the asynchronous read of the output stream.
    process.BeginOutputReadLine();

    String inputText;
    do 
    {
        inputText = Console.ReadLine();
        if (inputText == "q")
        {
            process.StandardInput.Close();   // After this line the output stream unblocks
            Console.ReadLine();
            return;
        }
        else if (!String.IsNullOrEmpty(inputText))
        {
            process.StandardInput.WriteLine(inputText);
        }
    }
}

, . , - Peek() EndOfStream.

?

+4
1

. , : . , .

"echoApp", , , (\n vs \r vs \r\n). , , .

use std::io;

fn main() {
    let mut counter = 0;
    loop {
        let mut input = String::new();
        let _ = io::stdin().read_line(&mut input);
        match &input.trim() as &str {
            "quit" => break,
            _ => {
                println!("{}: {}", counter, input);
                counter += 1;
            }
        }
    }
}

- , , F # # - :

open System.Diagnostics;

let echoPath = @"E:\R\rustic\echo\echoApp\target\debug\echoApp.exe"

let createControlledProcess path = 
    let p = new Process()
    p.StartInfo.UseShellExecute <- false
    p.StartInfo.RedirectStandardInput <- true
    p.StartInfo.RedirectStandardOutput <- true
    p.StartInfo.Arguments <- ""
    p.StartInfo.FileName <- path
    p.StartInfo.CreateNoWindow <- true
    p

let startupControlledProcess (p : Process) =
    if p.Start() 
    then 
        p.StandardInput.NewLine <- "\r\n"
    else ()

let shutdownControlledProcess (p : Process) =
    p.StandardInput.WriteLine("quit");
    p.WaitForExit()
    p.Close()

let interact (p : Process) (arg : string) : string =
    p.StandardInput.WriteLine(arg);
    let o = p.StandardOutput.ReadLine()
    // we get funny empty lines every other time... 
    // probably some line termination problem ( unix \n vs \r\n etc - 
    // who can tell what rust std::io does...?)
    if o = "" then p.StandardOutput.ReadLine()
    else o

let p = createControlledProcess echoPath
startupControlledProcess p
let results = 
    [
        interact p "Hello"
        interact p "World"
        interact p "Whatever"
        interact p "floats"
        interact p "your"
        interact p "boat"
    ]
shutdownControlledProcess p

f # interactive (CTRL-A ALT-Enter Visual Studio) :

val echoPath: string = "E:\R\rustic\echo\echoApp\target\debug\echoApp.exe"

val createControlledProcess: : →

val startupControlledProcess: p: Process → unit

val shutdownControlledProcess: p: Process → unit

val : p: → arg: →

val p: Process = System.Diagnostics.Process

val results: string list =

[ "0: Hello"; "1: "; "2: "; "3: "; "4: "; "5: " ]

val it: unit =()

- .. , , NewLine (. startupControlledProcess. , , , , .

+1

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


All Articles