起動したアプリケーションを終了させる |
自らが起動した他のアプリケーションを終了させるには
CreateProcess()で起動させプロセスハンドルを保持し
終了はTerminateProcess()で簡単に終了させる事が出来ます。
しかしこのAPIは有無を言わさずプロセスを強制終了させるので危険です。
出来る限り使わないほうが良いでしょう。
では安全に終了させるにはどうしたら良いかと言うと
起動したアプリケーション自らが終了する様に仕向けます。
方法としてはウィンドウハンドルを取得しWM_CLOSEを送るのが一般的です。
只、プロセスハンドルから直接ウィンドウハンドルを取得するAPI等は存在しません。
そこでウィンドウハンドルからウィンドウを作成したプロセスのIDを調られる
GetWindowThreadProcessId()というAPIを使用します。
つまり、全てのウィンドウハンドルを取得し、1つずつ作成したプロセスIDが
CreateProcess()で取得できるプロセスIDと一致するか調べるのです。
一致した場合、そのウィンドウは起動したアプリケーションのウィンドウと言う事です。
全てのウィンドウハンドルを取得する方法はEnumWindows()を使います。
このAPIは画面上のトップレベルのウィンドウハンドルをアプリケーション定義の
コールバック関数に順番に渡していく事を実現します。
コールバック関数とはWindowsから呼ばれる関数の事で
実際はアプリケーションが直接呼び出すものではありません。
Windowsはコールバック関数に色々なメッセージを繰り返し送ってきます。
コールバック関数内では送られたメッセージを独自の処理をする事が出来ます。
EnumWindows()は全てのトップレベルのウィンドウハンドルをWindowsから
コールバック関数に繰り返し呼ばせるようにします。
さて、コールバック関数の定義ですがここでは先に書いた様に
Windowsから送られたウィンドウハンドルからプロセスIDを取得し
CreateProcess()で取得したプロセスIDと比較。
それぞれが一致したらそのウィンドウにWM_CLOSEを送るという処理をします。
つまり以下の様になります。
// ウィンドウハンドルを取得しアプリケーションを終了させる。 BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { // CreateProcess()で取得したPROCESS_INFORMATION構造体のポインタを取得 PROCESS_INFORMATION* pi = (PROCESS_INFORMATION*)lParam; // ウインドウを作成したプロセスIDを取得。 DWORD lpdwProcessId = 0; ::GetWindowThreadProcessId(hWnd, &lpdwProcessId); // CreateProcessで起動したアプリのプロセスIDとメインウィンドウを // 作成したプロセスIDが同じ場合、起動したアプリを終了させる。 if(pi->dwProcessId == lpdwProcessId) { ::PostMessage(hWnd, WM_CLOSE, 0, 0); return FALSE; } return TRUE; } |
補足としてコールバック関数の名前はEnumWindowsProcでなくても構いません。
好きな名前を付けてもらって結構です。
それから戻り値でFALSEを返すとウィンドウハンドルの列挙が途中でも
中断して次は呼ばれなくなります。
あともう1つ大事な事で、コールバック関数はグローバル関数でなければなりません。
コールバック関数を呼び出すのはWindowsであるという事を考えると当然ですね。
それでは以下に実際の使用例を示します。
// メモ帳の起動。 STARTUPINFO si; PROCESS_INFORMATION pi; ::ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOWNORMAL; ::CreateProcess(NULL, _T("notepad"), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); AfxMessageBox(_T("メモ帳を終了させます。")); // コールバック関数の呼び出し。 EnumWindows(EnumWindowsProc, (LPARAM)&pi); // メモ帳が終了するまで待機し、もし5秒待っても終わらない時は強制終了させる。 if(::WaitForSingleObject(pi.hProcess, 5000) == WAIT_TIMEOUT) { if(AfxMessageBox(_T("強制終了させますか?"), MB_YESNO) == IDYES) TerminateProcess(pi.hProcess, 0); } ::CloseHandle(pi.hThread); ::CloseHandle(pi.hProcess); |
EnumWindows()の第一引数にコールバック関数名を(実際はポインタ)
第二引数に取得したPROCESS_INFORMATION構造体のポインタを渡します。
これで、メモ帳を起動しメッセージボックスをクリックする事で終了させられます。
この時メモ帳に何かを書いて保存しないでクリックすると
メモ帳が内容を保存するか聞いてきます。
ここで5秒待つと強制終了させるかどうかを選択する事になります。
「はい」ならそのまま終了させ「いいえ」なら終了させません。
< 戻る << HOME | ©1999-2001 by Akky, All right reserved. |