2011-07-03 5 views
3

私は小さなラッピングアプリケーションを使用して、既存のコンソールアプリケーションにGUIを提供しています。私はProcessStartInfoProcessクラスを使用して.exeにバインドし、次にBeginErrorReadLine()BeginOutputReadLine()を使用して、メッセージを新しいGUIにリダイレクトします。コンソールがConsole.Write()の代わりにConsole.WriteLine()を呼び出す場合を除き、すべてが正常に動作します。この場合、Writeに渡されるテキストはまったく表示されません。私は、WriteLine関数がテキストの後に改行を挿入し、Writeメソッドがそうでないために問題があると思うでしょう。これを回避する方法はありますか?元のコマンドラインプログラムのWriteからWriteLineに変更することはできません。入力を求めるプロンプトにはWriteが使用されています。プロセスの折り返し、一部の出力が表示されない

関連するコード:

var startInfo = new ProcessStartInfo(ServerFile); 
startInfo.RedirectStandardInput = true; 
startInfo.RedirectStandardError = true; 
startInfo.RedirectStandardOutput = true; 

ServerProc = new Process(); 
ServerProc.StartInfo = startInfo; 
ServerProc.EnableRaisingEvents = true; 
ServerProc.ErrorDataReceived += new DataReceivedEventHandler(ServerProc_ErrorDataReceived); 
ServerProc.OutputDataReceived += new DataReceivedEventHandler(ServerProc_OutputDataReceived); 

private void ServerProc_ErrorDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    Dispatcher.Invoke(new Action(() => 
    { 
     ConsoleTextBlock.Text += e.Data + "\r\n"; 
     ConsoleScroll.ScrollToEnd(); 
    })); 
} 

private void ServerProc_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    Dispatcher.Invoke(new Action(() => 
    { 
     ConsoleTextBlock.Text += e.Data + "\r\n"; 
     ConsoleScroll.ScrollToEnd(); 
    })); 
} 

答えて

2

発生している問題は、Processクラスは、プロセスの出力の便利な行指向イベントベースの処理のために設定されていることです。部分行が出力されているときにこの行を読み取る必要がある場合は、この機能を使用できません。

しかし、Processクラスは、ライン指向の機能よりも出力を細かく制御する必要がある場合に必要なツールを提供します。出力をリダイレクトする場合、Process.StandardOutputStreamReaderであり、行全体を強制的に読み取るのではなく、使用できるStreamReader APIがあります。例えば、ここでは文字単位で標準出力の読み取りが

されています:

var start = DateTime.Now; 
int n; 
while ((n = ServerProc.StandardOutput.Read()) != -1) 
{ 
    var c = (char)n; 
    var delta = (DateTime.Now - start).TotalMilliseconds; 
    Console.WriteLine("c = {0} (0x{1:X}) delta = {2}", 
     char.IsWhiteSpace(c) ? '*' : c, n, delta); 
} 

私たちは、この出力を生成し、別のコンソールプログラムでそれを実行した場合:

Console.Write("abc"); 
Thread.Sleep(1000); 
Console.WriteLine("def"); 

それが生成しますこの出力:

c = a (0x61) delta = 44.0025 
c = b (0x62) delta = 44.0025 
c = c (0x63) delta = 44.0025 
c = d (0x64) delta = 1109.0634 
c = e (0x65) delta = 1110.0635 
c = f (0x66) delta = 1110.0635 
c = * (0xD) delta = 1110.0635 
c = * (0xA) delta = 1110.0635 

これは、​​が1秒残りの行の前に。

ただし、イベント指向のI/Oが既にProcessで提供されているような場合は、この方法は便利ではありません。次のいずれかを実行できます

  • 非同期Stream APIブロッキングが

を読み取り、おそらくあなたのニーズに合った独自のイベント・ベースのI/Oを転がしん

  • 使用のスレッドを使用しています。

    他のプログラムの文字出力を解析するプログラムを作成しているため、フルラインを使用しないと、「今すぐプログラムが出力されていることを確認しました」という意味のタイムアウトが必要になります。これは、出力の予測可能性に応じて簡単または困難にすることができます。たとえば、"?"で終わるプロンプトを認識することができます。あなたの状況によって異なります。

    ライン指向のI/O以外のものが必要な場合は、StandardOutputStandardErrorStreamReaderプロパティを使用する必要があります。

  • +0

    Sladkey非同期読み込みと同期読み込みを使用する際の問題は、イベントベースではなく書き込み関数を手動で呼び出す必要があることです。これは正しいです?最高の解決策はタイマーのようなものでしょうか? – shmeeps

    +0

    プログラムの出力を解析するには、パーサーを書く必要があります。パーザをスレッドとして書くのが最も簡単です。そうしないと、状態マシンが必要になります。出力が確定的であれば、タイマーは一切必要ありません。タスクは簡単なものではなく、ソリューションはユーザーのニーズとアプリケーションによって異なります。設計には解析スレッドとの協調が必要であり、イベントを使用するのが最も簡単かもしれません。それ以外にも、実用的なアプローチがたくさんあります! –

    関連する問題