まずは、実行可能ファイルを実行するプロセスを作成してみます。
lpApplicationNameは実行ファイルの名前です。フルパスを指定しないときは カレントディレクトリのファイルが実行されます。拡張子がexeの時は省略可能です。BOOL CreateProcess( LPCTSTR lpApplicationName, // 実行可能モジュールの名前 LPTSTR lpCommandLine, // コマンドライン文字列 LPSECURITY_ATTRIBUTES lpProcessAttributes, // プロセスセキュリティ属性 LPSECURITY_ATTRIBUTES lpThreadAttributes, // スレッドセキュリティ属性 BOOL bInheritHandles, // ハンドルの継承の有無 DWORD dwCreationFlags, // プロセスの実行方法 LPVOID lpEnvironment, // 新しいプロセスの環境設定ポインタ LPCTSTR lpCurrentDirectory, // 新しいプロセスのカレントディレクトリ LPSTARTUPINFO lpStartupInfo, // STARTUPINFO構造体へのポインタ LPPROCESS_INFORMATION lpProcessInformation // PROCESS_INFORMATION構造体へのポインタ );
lpCommandLineにはコマンドラインを指定します。lpApplicationNameをNULLにしたときは 実行プログラム名も指定します。
lpProcessAttributesには、LPSECURITY_ATTRIBUTES構造体のポインタを指定します。
lpThreadAttributesには、LPSECURITY_ATTRIBUTES構造体のポインタを指定します。
bInheritHandlesには、新しいプロセスが親プロセスのハンドルを継承するかどうかを 指定します。
dwCreationFlagsには、プロセスの実行方法を指定します。
CREATE_DEFAULT_ERROR_MODE | 親プロセスのエラーモードを継承しない |
CREATE_NEW_CONSOLE | 新しいプロセスは新しいコンソールを持つ |
CREATE_NEW_PROCESS_GROUP | 新しいプロセスは新しいプロセスグループのルートになる |
CREATE_SEPARATE_WOW_VDM | 16ビットプログラムを別のprivate Virtual DOS Machine (VDM)で 開始する。(NT) |
CREATE_SHARED_WOW_VDM | 16ビットウィンドウプログラムを開始するときのみ有効(NT)。 |
CREATE_SUSPENDED | 新しいプロセスのプライマリスレッドをサスペンド状態にする。 |
CREATE_UNICODE_ENVIRONMENT | lpEnvironment環境変数でUNICODE文字セットを使う。 |
DEBUG_PROCESS | 呼び出し元がデバッグされている状態で新しいプロセスを作成する。 |
DEBUG_ONLY_THIS_PROCESS | 現在のデバッグ状態を子供に接続しない。 |
DETACHED_PROCESS | コンソールプロセスに対して、新しいプロセスはコンソールを持たない。 |
この他に優先順位クラスを加えることができます。
HIGH_PRIORITY_CLASS | 高優先順位クラス |
IDLE_PRIORITY_CLASS | 最低優先順位クラス |
NORMAL_PRIORITY_CLASS | 普通の優先順位 |
NORMAL_PRIORITY_CLASS | プリエンプティブ方式のOSの動作を均等に割り当てる |
lpEnvironmentは、新しいプロセスの環境設定ポインタを指定します。
name = value
という一連のNULLで終わる文字列で指定して、最後に2つのNULLをつけます。
lpCurrentDirectoryには、新しいプロセスのカレントディレクトリとして使用するパスを指定します。 NULLを指定すると呼び出し元と同じディレクトリとなります。
lpStartupInfoには、表示形式を指定します。
lpProcessInformationには、PROCESS_INFORMATION構造体のポインタを指定します。
成功すると0以外が返されます。
さて、CreateProcess関数で作成したプロセスが終了しても、プロセスのハンドルや スレッドのハンドルはシステム内に残ります。(不要になったらすぐにCloseHandleする)
nLengthはこの構造体の大きさです。typedef struct _SECURITY_ATTRIBUTES { // sa DWORD nLength; LPVOID lpSecurityDescriptor; BOOL bInheritHandle; } SECURITY_ATTRIBUTES;
lpSecurityDescriptorはセキュリティデスクリプタへのポインタです。Windows95/98では無視されます。
bInheritHandleは、新しいプロセスが作られたときにハンドルを継承するかどうかを指定します。
STARTUPINFO構造体は次のように定義されています。それぞれのメンバの意味は コメントを参考にしてください。
PROCESS_INFORMATION構造体は次のように定義されています。typedef struct _STARTUPINFO { // si DWORD cb; //構造体の大きさ LPTSTR lpReserved; //予約済み LPTSTR lpDesktop; //NT用 LPTSTR lpTitle; //コンソールアプリのタイトル DWORD dwX; //x位置 DWORD dwY; //y位置 DWORD dwXSize; //幅 DWORD dwYSize; //高さ DWORD dwXCountChars; //コンソールの幅(キャラクタ単位) DWORD dwYCountChars; //コンソールの高さ DWORD dwFillAttribute; //コンソールの前景および背景色 DWORD dwFlags; //どのメンバが有効か WORD wShowWindow; //ウィンドウの表示のパラメータ(ShowWindow) WORD cbReserved2; LPBYTE lpReserved2; HANDLE hStdInput; //入力用ハンドル HANDLE hStdOutput; //出力用ハンドル HANDLE hStdError; //エラーハンドル } STARTUPINFO, *LPSTARTUPINFO;
hProcessは新しいプロセスのハンドルです。typedef struct _PROCESS_INFORMATION { // pi HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION;
hThreadは新しいプロセスのメインスレッドのハンドルです。
dwProcessIdはプロセスIDです。
dwThreadIdはスレッドIDです。
では、プログラムを見てみましょう。これはメニューの 「子プロセスを起動」で「ファイルを開く」コモンダイアログが出てきます。 ここで、起動したいexeを選択すると、それが起動します。
メニューのリソース・スクリプトです。// process01.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "プロセス(&P)" BEGIN MENUITEM "子プロセスを起動(&C)", IDM_PRO END END
簡単なので一気に表示しました。CreateProcess関数が実行されたあと、特にプロセスや スレッドのハンドルは不要なので、直ちにCloseHandleしています。// process01.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void MyChildProcess(HWND); char szClassName[] = "process01"; //ウィンドウクラス int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるプロセス", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } //ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_PRO: MyChildProcess(hWnd); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; } void MyChildProcess(HWND hWnd) { OPENFILENAME ofn; char szFile[MAX_PATH], szTitle[MAX_PATH]; STARTUPINFO si; PROCESS_INFORMATION pi; memset(&ofn, 0, sizeof(OPENFILENAME)); strcpy(szFile, ""); strcpy(szTitle, ""); memset(&si, 0, sizeof(STARTUPINFO)); memset(&pi, 0, sizeof(PROCESS_INFORMATION)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = "プログラム(*.exe)\0*.exe\0全て(*.*)\0*.*\0\0"; ofn.lpstrFile = szFile; ofn.lpstrFileTitle = szTitle; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = "exe"; ofn.lpstrTitle = "起動する子プロセスを選択"; ofn.nMaxFileTitle = MAX_PATH; GetOpenFileName(&ofn); CreateProcess(NULL, szFile, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (CloseHandle(pi.hProcess)) MessageBox(hWnd, "プロセスハンドルの破棄成功", "OK", MB_OK); if (CloseHandle(pi.hThread)) MessageBox(hWnd, "スレッドハンドルの破棄成功", "OK", MB_OK);; return; }
新しく作ったプロセスと連絡をとりたいときは、どうすればよいのでしょうか。 今までもいくつか出てきました。復習してみてください。
Update 24/Nov/1999 By Y.Kumei