外部プロセスとして起動したバッチファイルの終了を待とう〜c#編


やあ子どもたち元気にしているか。
よくC#ASP.NETなんかをやっていて、「バッチファイルを外部プロセスとして起動したいが、とくにそれが終了するまで処理を待ちたい」なんていうことを考えたことが誰しもあることと思う。
そんな時に活躍するのが、Process.Start()だったり、WaitForExit()だったりするわけだが、起動するのが.exeではなしにバッチファイルである場合、とくにWaitForExit()でその終了を捕まえるためにはバッチファイルが起動されるしくみについて若干考えなくてはならないTipsがあって、それが今回のメモの内容だよ。
結論から言うとそれをやるための方法は以下のようになる。

  // ●プロセス起動情報の構築
  ProcessStartInfo startInfo = new ProcessStartInfo(); 

  // バッチファイルを起動する人は、cmd.exeさんなので
  startInfo.FileName = "cmd.exe"; 

  // コマンド処理実行後、コマンドウィンドウ終わるようにする。
  //(↓「/c」の後の最後のスペース1文字は重要!)
  startInfo.Arguments = "/c "; 

  // コマンド処理であるバッチファイル (ここも最後のスペース重要)
  startInfo.Arguments += @"d:\bin\YourBatFile.bat ";

  // バッチファイルへの引数 
  startInfo.Arguments += YourArgStrings;

  // ●バッチファイルを別プロセスとして起動
  var proc = Process.Start(startInfo); 

  // ●上記バッチ処理が終了するまで待ちます。
  proc.WaitForExit(); 

説明しよう、バッチファイルというものは、cmd.exeというプログラムがバッチファイルを第一引数にとり、(さらにそのバッチファイルの引数が第二引数以降に続いたりしながら)これが実行されることによって、バッチファイル本体が実行されるわけなんだ。
それでここが大事なのだが、それだけだと、当のバッチファイルの実行が終了しても、cmd.exe自体が終了しないということがある。よくデスクトップでバッチファイルをダブルクリックさせた時に出るあの黒画面が出たままの状態のようなイメージだ。これがですよ、これがためにだね、WaitForExit()で待ってもいつまで経っても帰ってこないことになる。そこで登場するのが、cmd.exeの「/c」オプションだ。これを指定すると、バッチファイルの処理が完了した次第でcmd.exe自体を終了することが保証される。なので、バッチファイルの起動におけるコマンドラインとしては、

cmd.exe /c YourBatFile.bat YourArg1 YourArg2 .. 

という格好になるわけで、それを、Process.Start()で同じ事をやる場合の書き方が、上記のソースのようになるということなんだね。
実はProcess.Start()に、バッチファイルの名前をそのまま渡してもバッチファイルの起動自体はする。しかし、それは内部で、cmd.exeを起動するように書き換えられているだけで、とくにその場合、「/c」オプションは指定されないようなのだ。なので、今回のように、cmd.exeを起動するところから明示的に書いてあげて、同オプションをしっかり入れてあげる必要がある、という、こういうわけなんだね。
大事なことがもう一つ。そう、おじさんはこれがために随分と途方に暮れかけてしまったのでここにメモしておくぞ。ASP.NETのプログラムをC#で書いていて、その中で上記のようなバッチファイル呼び出しをしたい場合は、上記コードのままだとProcess.Start()を読んだ時点で、エラーになってしまったりする。再起動したらしばらくは大丈夫になるけどまた突然、エラーが出たり。。再現性のないバグの森の中の沼にズブズブと沈んでいってしまうよ恐ろしい話だね!そういう現象がある場合に一番有力なバグ要素はなんだと思うかい?そう、未初期化だ。初期化忘れはしばしば再現性のないエラーを返すよおそろしいね。
この場合に必要なのは、Process.Start()を呼び出す前に以下の2行を忘れずに入れることだ。

    startInfo.UseShellExecute = false;
    startInfo.CreateNoWindow = true;

そう、ASPやってる場合は、ウィンドウが要らないということをこのように明示的に指定してやらないとだめなんだね。
いかがだろうかじゃ今日はこのへんでもう寝ることにしよう。チャオ!

Variations on the Kanon

Variations on the Kanon