まずは、次のプログラム(childprocess01.exe)を作っておきます。
/* childprocess01.c */
#include <stdio.h>
#include <conio.h>
int main()
{
printf("\n子プロセスです\n");
printf("何かキーを押すと終了します\n");
_getch();
return 0;
}
ごく簡単なコンソールアプリケーションです。
このプログラムを他のプログラムの子プロセスとして起動することを考えてみましょう。
新しいプロセスを作成するには、CreateProcess関数を使います。
BOOL CreateProcess( LPCTSTR lpApplicationName, // 実行可能モジュールの名前 LPTSTR lpCommandLine, // コマンドラインの文字列 LPSECURITY_ATTRIBUTES lpProcessAttributes, // セキュリティ記述子 LPSECURITY_ATTRIBUTES lpThreadAttributes, // セキュリティ記述子 BOOL bInheritHandles, // ハンドルの継承オプション DWORD dwCreationFlags, // 作成のフラグ LPVOID lpEnvironment, // 新しい環境ブロック LPCTSTR lpCurrentDirectory, // カレントディレクトリの名前 LPSTARTUPINFO lpStartupInfo, // スタートアップ情報 LPPROCESS_INFORMATION lpProcessInformation // プロセス情報 );いろいろ引数があって面倒そうですね。
lpApplicationNameは実行ファイルの名前です。フルパスを指定しないときはカレントディレクトリのファイルが実行されます。拡張子がexeの時は省略可能です。
lpCommandLineにはコマンドラインを指定します。lpApplicationNameをNULLにしたときは実行プログラム名も指定します。
lpProcessAttributesには、LPSECURITY_ATTRIBUTES構造体のポインタを指定します。
lpThreadAttributesには、LPSECURITY_ATTRIBUTES構造体のポインタを指定します。
bInheritHandlesには、新しいプロセスが親プロセスのハンドルを継承するかどうかを指定します。
dwCreationFlagsには、プロセスの実行方法を指定します。
lpEnvironmentは、新しいプロセスの環境設定ポインタを指定します。
lpCurrentDirectoryには、新しいプロセスのカレントディレクトリとして使用するパスを指定します。 NULLを指定すると呼び出し元と同じディレクトリとなります。
lpStartupInfoには、表示形式を指定します。
lpProcessInformationには、PROCESS_INFORMATION構造体のポインタを指定します。
成功すると0以外が返されます。
ここでは、STARTUPINFO構造体や、PROCESS_INFORMATION構造体の詳しい解説はしません。プログラミングで必要となるメンバは限られています。
ここでは、最も簡単な例として
STARTUPINFO si;
PROCESS_INFORMATION pi;
CreateProcess(NULL,
"childprocess01",
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi);
とします。引数のほとんどは0または、NULLです。これで、childrocess01.exeを起動することができます。
さて、子プロセスを起動した場合、このプロセスがどうなっているか(プロセスがすでに終了しているのかどうか)を調べる一番簡単な方法は、GetExitCodeProcess関数を使うことです。
BOOL GetExitCodeProcess( HANDLE hProcess, // プロセスのハンドル LPDWORD lpExitCode // 終了ステータス );さて、プロセスのハンドルはどのようにしてわかるのでしょうか。
これは、CreateProcess関数を実行したとき、PROCESS_INFORMATION構造体のhProcessメンバに格納されています。
プロセスが終了していない場合は、終了ステータスにSTILL_ACTIVEが格納されます。
終了している場合は、main関数または、WinMain関数の戻り値が格納されます。
ただし、TerminateProcess関数などで強制的に終了したときは、その関数で指定した終了コードが格納されます。
また、CreateProcess関数で作成したプロセスが終了してもこのプロセスのプロセスハンドル、スレッドハンドルはシステム内に残ってしまうのでCloseHandle関数でクローズしなくてはいけません。
では、CreateProcess関数で最初に作ったchildprocess01.exeを起動して、このプログラムが終了したら、自分も終了するプログラムを作ってみましょう。
/* multiprocess01.c */
#include <stdio.h>
#include <windows.h>
int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD dwExCode;
memset(&si, 0, sizeof(STARTUPINFO));
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
printf("子プロセスを呼び出します\n");
CreateProcess(NULL,
"childprocess01",
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi);
while (1) {
Sleep(100);
GetExitCodeProcess(pi.hProcess, &dwExCode);
if (dwExCode == STILL_ACTIVE) {
continue;
} else {
printf("子プロセスは終了したようです\n");
break;
}
}
if(CloseHandle(pi.hProcess))
printf("プロセスハンドルを閉じました\n");
if(CloseHandle(pi.hThread))
printf("スレッドハンドルを閉じました\n");
printf("親プロセスを終了します\n");
return 0;
}
では、実行結果を見てみましょう。
子プロセスの終了を待つ方法としては必ずしも良い方法とは言えません。
少しずつ、いろいろなことを解説していきます。
Update Jun/02/2005 By Y.Kumei