CreateProcessによるプログラム起動と制御

CreateProcess()を使うと任意のプログラムをコマンドラインで、あるいは引数付で実行することができます。さらに、実行開始時の状態を指定したり実行したプロセスやプロセスのメインスレッドのハンドルも得られるので、プログラムの終了を待つなど柔軟な制御ができそうですね。
適当なエディタ機能とCreateProcess()を組み合わせれば、「編集したソースをコマンドラインでコンパイラに渡してコンパイル、コンパイル終了を待って実行」という簡単な「統合開発環境」を開発することもできるでしょう。

今回は、そうした他のプログラムとの連携を意識しCreateProcess()で任意のコマンドラインを指定してプログラムを実行し、そのプログラムの終了を検知してみることにします。

CreateProcessによる制御

 まず、CreateProcess()でプログラムを起動してみましょう。CreateProcess()では、プログラムの実行ファイル名を指定することもできますが、コマンドラインの文字列に引数などと一緒にプログラム名を指定した方が楽でしょう。CreateProcess()で最低限指定する必要があるのは、コマンドラインの他実行開始時の状態を指定するSTARTUPINFO構造体と起動したプロセスのハンドルなどが格納されるPROCESS_INFORMATION構造体のアドレスです。ただし、STARTUPINFO構造体は通常はサイズ以外は0で良いでしょう。
実際の使用例は、以下のような感じです(lpArgがコマンドライン)。

CreateProcess使用例


  PROCESS_INFORMATION pi;
  STARTUPINFO si;

  ZeroMemory(&si,sizeof(si));
  si.cb=sizeof(si);

  CreateProcess(NULL,(LPTSTR)lpArg,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
    NULL,NULL,&si,&pi);

これでlpArgで指定されたコマンドラインが実行され、その結果起動したプロセスやプロセスのメインスレッドのハンドルなどがpiに格納されます。起動するだけなら、この後piに格納されているハンドルを閉じるだけ。起動したプロセスやプロセスのメインスレッドを制御する場合は、piのハンドルを使用して実際の処理を行うことになります。

今回は、起動したプロセスの終了を検知する事が目的なので、起動したプロセスのハンドルpi.hProcessがシグナル状態になるまで待つ事にしましょう。プロセスのハンドルがシグナル状態になるまで待つには、WaitForSingleObject()に待機時間INFINITEを指定してハンドルを渡します。これで、プロセスがシグナルになるまで制御が返らないので、WaitForSingleObject()から戻ってくればプロセスも終了しているわけですね。

プロセスを起動してその終了を待つ処理は以下のようになるでしょう。

  PROCESS_INFORMATION pi;
  STARTUPINFO si;

  ZeroMemory(&si,sizeof(si));
  si.cb=sizeof(si);

  CreateProcess(NULL,(LPTSTR)lpArg,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
    NULL,NULL,&si,&pi);

  CloseHandle(pi.hThread);

  WaitForSingleObject(pi.hProcess,INFINITE);

  CloseHandle(pi.hProcess);

ただ、これだとWaitForSingleObject()で処理が止まってしまうためプロセス終了まで何もできず、ウインドウプログラムではユーザーの操作にも応答できなくなってしまいます。それでは都合が悪いので、今回はこの部分をスレッド関数にしてメインウインドウのウインドウプロシージャーから別スレッドで起動するマルチスレッドのプログラムにしました。
スレッドでは、プロセスが終了したらメインウインドウにメッセージを送信してプロセスの終了を通知するようにします。

  DWORD WINAPI func(LPVOID lpArg) {

      PROCESS_INFORMATION pi;
      STARTUPINFO si;

      ZeroMemory(&si,sizeof(si));
      si.cb=sizeof(si);

      CreateProcess(NULL,(LPTSTR)lpArg,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
        NULL,NULL,&si,&pi);

      CloseHandle(pi.hThread);

      WaitForSingleObject(pi.hProcess,INFINITE);

      CloseHandle(pi.hProcess);

      PostMessage(hwMain,WM_USER,0,0);

      ExitThread(0);

      return 0;

  }

プログラム

今回のサンプルは、指定のコマンドラインを起動し、別スレッドで終了を待機するマルチスレッドのプログラムになっています。

プログラムソース表示

実行したら入力欄に適当なコマンドライン(notepadなど)を入れ、実行ボタンをクリックしてください。プログラムが起動し、ボタンの文字列が「実行中」に変化します。プログラムを終了するとボタンの文字列も実行に戻り、再度実行できるようになります。このプログラムを終了する時には、その前に実行ボタンで起動したプログラムを終了するようにしてください。