2017-08-03 7 views
4

対話型コマンドラインプログラムのラッパーを記述する必要があります。別の.NETプログラムからの対話型コマンドラインプログラムの使用方法

これは、標準入力を介して他のプログラムにコマンドを送信し、標準出力を介して応答を受け取ることができる必要があることを意味します。

入力ストリームが開いている間に標準出力ストリームがブロックされているように見えることが問題です。私が入力ストリームを閉じると、私は応答を得ます。しかし、私はより多くのコマンドを送ることはできません。

これは私が(ほとんど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でも可能です。

全二重の方法で他のプロセスと通信する手段はありますか?

+0

非同期スレッド? –

+0

@BenderBendingはい私はできるが、これは助けになるだろうか? – Karsten

+0

私はそう思う。一方のスレッドの入力ストリームと他方のスレッドの出力ストリーム –

答えて

1

私自身の小さなテストスイートで問題を再現しようとしました。 イベントハンドラを使用するのではなく、私が考えることのできる最も些細な方法でそれを行います。このようにして、問題に余分な複雑さが加えられることはありません。ここで

私の小さな「echoAppは、」私は笑いのために、錆に書いても、永遠の回線終端戦争の問題に遭遇するチャンス(\r\n\r\n)を持っています。コマンドラインアプリケーションの記述方法によっては、これが実際にあなたの問題の1つになる可能性があります。

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; 
      } 
     } 
    } 
} 

そして - - このような小さなテストのためのソリューションを作成するようにしない怠惰な骨であること、私が代わりに制御側のC#の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 

ヴァルechoPath::文字列=「E:\ R \素朴\エコー\ echoApp \ターゲット\デバッグ\ echoApp F(CTRL-のVisual StudioでALT-Enter)をインタラクティブ#収率でこれを実行

。 exe "

ヴァルcreateControlledProcess:パス:文字列 - >プロセス

ヴァルstartupControlledProcess:P:プロセス - >単位

ヴァルshutdownControlledProcess:P:プロセス - >単位

ヴァル相互作用:P:プロセス - >引数:文字列 - >文字列

val p:Process = System.Diagnostics。プロセス

値の結果:文字列リスト=

["0:こんにちは"; "1:世界"; "2:何でも"; 「3:浮動」 "4:あなた"; 「5:ボート」]

ヴァルそれ:単位=()

私はそうなど を任意のブロックやデッドロックを再現することができませんでした、あなたのケースでは、私は多分あなたのNewLine財産のニーズかどうかを調査しようとするだろう制御されたアプリケーションが入力を行として認識しない場合、それは応答せず、入力行の残りの部分をまだ待っており、結果が得られる可能性があります。

+0

あなたの広範な答えをありがとう!私は成功しなかった '新ライン'のために異なる値を試しました。私も同様の結果を持つpythonからプロセスを開始しようとしました。私はそれが他のアプリケーションが書かれている方法と関係があると思う。私はそれがコマンドラインからはるかに良い仕事をした別個のWinSCP.comファイルを持っていることを発見するまで、私はWinSCPで同様の問題を抱えていました。私はまだ2つの違いが何であるか分かりませんが、私が知る限り、プログラムする方法はありません。 – Karsten

+0

ターゲットプログラムが特定の作業ディレクトリに依存しているかどうか試してみる必要があります。いくつか(ひどく書かれた)プログラムがそうしています。これにより、プログラムが動作しなくなる可能性があります。あるいは、おそらく、UNIX環境から来る多くのプログラムが環境設定に依存しているかもしれません。アプリケーションを起動すると、作業ディレクトリと環境設定(多分PATH?)を指定することができます。 – BitTickler

関連する問題