| 起動したアプリケーションを終了させる |
自らが起動した他のアプリケーションを終了させるには
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. |