1

コマンドプロンプトウィンドウを実行し、プログラムを実行して出力を読み取るために、次のコード(チュートリアルから採用)を実装しました。このコードは、ユーザーコントロールにネストされているButtonClickイベントハンドラーから呼び出されます。

メソッドが「非同期」であるため、これにより、外部プロセスの実行中にプログラムの残りの部分が機能するようになるという印象を受けました。ただし、操作の実行中に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

3 に答える 3

4

あなたの問題はここにあります:

cmd.WaitForExit();

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

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

于 2012-04-12T15:53:20.690 に答える
4

Exitedイベントに登録して、MessageBoxそこに表示するのはどうですか。

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

MSDNから:

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

于 2012-04-12T15:58:58.743 に答える
2

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

BackgroundWorkerをチェックしてください。

于 2012-04-12T15:53:47.280 に答える