2012-04-12 16 views
1

コマンドプロンプトウィンドウを実行し、プログラムを実行して出力を読み取るために、次のコード(tutorialから適合)を実装しました。このコードは、UserControlにネストされたButtonClickイベントハンドラから呼び出されます。外部プロセスを使用したUIのフリーズ

これは、メソッドが「非同期」であるため、外部プロセスが実行されている間、残りのプログラムが機能することができるという印象を受けました。ただし、操作が実行されている間、私のUIがフリーズするので、これは当てはまりません。私は、cmdプロセスが終了したときに受け取った出力が正しいことを付け加えるべきです。

申し訳ありませんが、このようなコードの読み込みをダンプするには、この時点で何をすべきかわかりません。

ご協力いただければ幸いです。

public static void runExternalProcess() 
{ 
    StringBuilder output = new StringBuilder(); 

    Process cmd = new Process(); 
    cmd.StartInfo.FileName = "cmd.exe";   
    cmd.StartInfo.UseShellExecute = false; 
    cmd.StartInfo.CreateNoWindow = true; 
    cmd.StartInfo.RedirectStandardOutput = true; 

    cmd.OutputDataReceived += new DataReceivedEventHandler(outputEventHandler);   
    cmd.StartInfo.RedirectStandardInput = true;   
    cmd.Start(); 
    cmd.BeginOutputReadLine();  

    StreamWriter sortStreamWriter = cmd.StandardInput; 
    StreamWriter sw = cmd.StandardInput; 

    if (sw.BaseStream.CanWrite) 
    { 
     sw.WriteLine("ping www.google.com"); 
    } 

    sw.Close(); 

    cmd.WaitForExit(); 

    MessageBox.Show(output.ToString()); 

    cmd.Close(); 
} 

private static void outputEventHandler(object sendingProcess, DataReceivedEventArgs e) 
{ 
    if (!String.IsNullOrEmpty(e.Data)) 
    { 
     output.Append(e.Data + Environment.NewLine); 
    } 
} 

答えて

4

どうExitedイベントに登録してMessageBoxが表示について:MSDNから

StringBuilder output = new StringBuilder(); 
Process cmd = new Process(); 

public void RunExternalPing() 
{ 
    cmd.StartInfo.FileName = "cmd.exe"; 
    cmd.StartInfo.UseShellExecute = false; 
    cmd.StartInfo.CreateNoWindow = true; 
    cmd.StartInfo.RedirectStandardOutput = true; 
    cmd.StartInfo.RedirectStandardInput = true; 

    cmd.EnableRaisingEvents = true; 
    cmd.OutputDataReceived += 
     new DataReceivedEventHandler(cmd_OutputDataReceived); 
    cmd.Exited += new EventHandler(cmd_Exited); 

    cmd.Start(); 
    cmd.BeginOutputReadLine(); 
    StreamWriter sw = cmd.StandardInput; 
    sw.WriteLine("ping www.google.com"); 
    sw.Close(); 
} 

void cmd_Exited(object sender, EventArgs e) 
{ 
    MessageBox.Show(output.ToString()); 
    cmd.Dispose(); 
} 

private void cmd_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    if (!String.IsNullOrEmpty(e.Data)) 
    { 
     output.Append(e.Data + Environment.NewLine); 
    } 
} 

関連付けられたプロセスが終了し たときに通知されているのは2つの方法があります:同期と非同期。同期通知 は、WaitForExitメソッドを呼び出して、関連付けられたコンポーネントが終了するまでアプリケーションの処理を一時停止します( )。非同期 通知は、Exitedイベントに依存します。いずれの場合も、プロセスコンポーネントが にEnableRaisingEventsを設定して、プロセスが終了したという通知を に送信する必要があります。

+0

上記のコードで追加したが、watiforexit()呼び出しを削除しましたが、関数はメッセージボックスを表示しません。 –

+0

'cmd.WaitForExit();'を削除しましたか? – SwDevMan81

+0

はい残念ですが、遅いです(そしてコメントを編集しました)。メッセージボックスは今ではまったく表示されません。なぜあなたはどんな考えがありますか? –

4

あなたの問題はここにある:

cmd.WaitForExit(); 

これは、ブロッキング呼び出しです。

ブロックしないで終了するプロセスに応答する場合は、Exitedイベントのハンドラを追加する必要があります。

+0

彼らは 'MessageBox.Show'を呼び出す前に出力を待つ必要があります。 – Matthew

+1

@Matthew:はい、なぜ彼らが待っているのか分かります。私は彼らのUIをなぜブロックするのかを彼らに伝えています。 –

+0

ああ、あなたが言っていることが分かります。あなたが示唆していたことに対する私の印象は、その行だけを削除することでした。 – Matthew

2

このコードはすべて線形です。現在のスレッドをフリーズしたくない場合は、新しいスレッドを作成し、そのスレッドが終了したときにコールバックを実行する必要があります。

チェックアウトBackgroundWorker

+0

あなたが私の質問に気をつけなければ、非同期メソッドを使用する利点は何ですか? –

+1

@ Mr.Spice関数 'WaitForExit'は非同期ではないので、あなたのスレッドはブロックされています。 – Matthew

+0

ああ、ありがとうございます。 –

関連する問題