コンソールアプリケーションの出力をキャプチャーしてプログレスバーを表示する

既存にあるコンソールアプリケーションの出力を読み取り、フォーム上のプログレスバーに処理の進捗状況を表示する。
コンソールアプリケーションの出力としては最初に総処理ステップ数、次に進捗状況に合わせた出力。そして最後に終了を表す文字列が出力されるものとしている。



例)コンソールアプリケーションの出力
Total Steps:10
1/10
2/10
3/10
:
:
10/10
Done!


コンソールアプリケーションはProcessクラスを使って別プロセスで起動する。
ポイントになるのはコンソールアプリケーションからの出力の取得方法。
以下の例ではOutputDataReceivedイベントに処理用のハンドラを用意して処理を行っている。
少々厄介なのはイベントハンドラからフォーム上のコントロールを直接変更しようとするとInvalidOperationExceptionが発生する点。(イベントハンドラがフォームを所有するとスレッドとは別物になるため?)
このため例ではInvokeメソッドを使ってスレッドセーフな方法でフォーム上のコントロールの操作を行っている。



また、アプリケーションを起動した側のスレッドで"WaitForExit()"をコメントアウトしてある。これはコンソールアプリケーションの処理が長時間に渡る場合、その間フォームが待ち状態でフリーズしたようになるのを避けるため。



private void button1_Click(object sender, EventArgs e)

{

Process process = ne Process();

ProcessStartInfo pi = new ProcessStartInfo();

pi.UseShellExecute = false;
pi.RedirectStandardOutput = true;
pi.CreateNoWindow = true; //

ウィンドウを表示しない(コンソールアプリケーションをバックグランドで実行する)

pi.WorkingDirectory = @"C:\WorkingFolder"; // 作業フォルダ

pi.FileName = @"ConsoleApp.exe"; // 実行するコンソールアプリケーション

process.StartInfo = pi;

process.OutputDataReceived += new DataReceivedEventHandler(OutputDataReceivedEventHandler);// イベントハンドラを指定
process.Start();

process.BeginOutputReadLine();
//process.WaitForExit();
// コンソールアプリケーションが終了するまでWindowsのメッセージを処理する

while (process.HasExited != true)
{
System.Threading.Thread.Sleep(100); // ミリ秒で指定
Application.DoEvents();
}
}

// イベントハンドラ

private void OutputDataReceivedEventHandler(object sender, DataReceivedEventArgs output)

{
if (!String.IsNullOrEmpty(output.Data))

{

if (String.IsNullOrEmpty(output.Data)) return;

if (output.Data.StartsWith("Total Steps:"))

{

string[] lines = output.Data.Split(new char[] { ':' });

int max = int.Parse(lines[1]);

SetProgressBarMax(max);

}

if (output.Data.Contains("/"))

{

string[] lines = output.Data.Split(new char[] { '/' });

int val = int.Parse(lines[0]);

SetProgressBar(val);

}

}

}

delegate void SetProgressBarMaxCallback(int value);

private void SetProgressBarMax(int value)

{

if (this.progressBar1.InvokeRequired)

{

SetProgressBarMaxCallback d = new SetProgressBarMaxCallback(SetProgressBarMax);

this.Invoke(d, new object[] { value });

}
else
{
this.progressBar1.Maximum = value;
}
}

delegate void SetProgressBarCallback(int value);

private void SetProgressBar(int value)

{
if (this.progressBar1.InvokeRequired)
{
SetProgressBarCallback d = new SetProgressBarCallback(SetProgressBar);
this.Invoke(d, new object[] { value });
}
else
{
this.progressBar1.Value = value;
}
}

コメント

このブログの人気の投稿

TabError: inconsistent use of tabs and spaces in indentation

マクロを含んだ.XLSがExcel2010で開けない

using ディレクティブまたはアセンブリ参照が不足しています。