プロセスID からウィンドウハンドルを取得する方法です。
プロセスIDからウィンドウハンドルを探す Win32API は無いようです。EnumWindows()して探します。EnumWindows()のコールバックに渡されたウィンドウハンドルからプロセスIDを取得して、探したいプロセスIDと一致したウィンドウハンドルを拾っていきます。
次のような関数 FindHwndFromPid() を作って取得できるようにします。FindHwndFromPid() はプロセスIDに一致する全てのウィンドウハンドルを取得して std::vector<HWND> に格納します。
DWORD pid; // 探したいプロセスID
std::vector<HWND> hWnds = std::vector<HWND>(); // 探したウィンドウハンドルを格納する領域
FindHwndFromPid(pid, hWnds);
コード
コードは次の通りです。FindHwndFromPid() は17行目です。
// _EnumWindowsProc() に渡す構造体
struct _EnumWindowsArg {
DWORD targetPid; // 検索対象のプロセスID
std::vector<HWND> *foundWindowHandles; // 一致したウィンドウハンドルが格納される
_EnumWindowsArg(DWORD targetPid, std::vector<HWND>& foundWindowHandles) {
this->targetPid = targetPid;
this->foundWindowHandles = &foundWindowHandles;
}
};
/*
* FindHwndFromPid()
* pid : 指定した pid (プロセスID) に一致するウィンドウハンドルを探す。
* hWnds : pid に一致したウィンドウハンドルのリストが格納される。
*/
void FindHwndFromPid(DWORD pid, std::vector<HWND>& hWnds)
{
_EnumWindowsArg args = _EnumWindowsArg(pid, hWnds);
EnumWindows((WNDENUMPROC)_EnumWindowsProc, (LPARAM)&args);
}
// EnumWindows に呼んで貰うコールバック関数
BOOL __stdcall _EnumWindowsProc(HWND hWnd, LPARAM lp)
{
_EnumWindowsArg *args = (_EnumWindowsArg*)lp;
// hWnd → pid を取得して、探している pid でなければスキップする
DWORD pid;
if (GetWindowThreadProcessId(hWnd, &pid) == 0) return TRUE;
if (pid != args->targetPid) return TRUE;
// 見つかったウィンドウハンドルをリストに追加する。
args->foundWindowHandles->push_back(hWnd);
// _EnumWindowsProc を継続して次へ
return TRUE;
}
struct _EnumWindowsArg
EnumWindows() に探したいプロセスID と 探したウィンドウハンドルを格納する std::vector<HWND> を渡したいため構造体を用意しています。FindHwndFromPid() で生成して EnumWindows() に渡しています。
FindHwndFromPid()
プロセスIDからウィンドウハンドルを探す関数 FindHwndFromPid() 本体です。
FindHwndFromPid() は EnumWindows()を実行しています。
_EnumWindowsProc()
EnumWindows() のコールバック関数です。引数で渡された hWnd からプロセスIDを取得して一致するか判定して、一致したウィンドウハンドルを _EnumWindowsArg構造体の *foundWindowHandles に格納しています。
実行例 メモ帳のプロセスIDを指定したときの出力
FindHwndFromPid()を実行してコンソールに出力するプログラム
実際にプロセスIDを指定してリストが取得できるかを確認してみます。第一引数にプロセスIDを指定してコンソールに表示するプログラムを作ります。_GetModuleNameFromPid()、_GetClassName()、_GetCaption() は情報取得用の関数ですが、本題ではないので省略しています。
int _tmain(int argc, _TCHAR* argv[])
{
// 第一引数で指定された pid を数値にする
DWORD pid = atoi(AnsiString(UnicodeString(argv[1])).c_str());
// pid と実行可能ファイル名を出力する
UnicodeString moduleName = _GetModuleNameFromPid(pid);
printf("pid=%d exename=%s\n\n", pid, AnsiString(moduleName).c_str());
// FindHwndFromPid() を実行する
std::vector<HWND> hWnds = std::vector<HWND>();
FindHwndFromPid(pid, hWnds);
// 取得できたウィンドウハンドルの情報を表示する
printf("hWnd className / caption\n");
printf("---------- ---------------------------------------------\n");
std::vector<HWND>::iterator it;
for (it = hWnds.begin(); it != hWnds.end(); it++) {
HWND hWnd = *it;
UnicodeString ClassName = _GetClassName(hWnd);
UnicodeString WindowCaption = _GetCaption(hWnd);
printf("0x%08x %s / %s\n", hWnd, AnsiString(ClassName).c_str(), AnsiString(WindowCaption).c_str());
}
printf("---------- ---------------------------------------------\n");
}
実行結果
メモ帳のプロセスID「25584」を指定して実行すると次のように表示されました。プロセスIDに対応する全てのウィンドウハンドルが取得できていることが確認できました。
> .\Project1.exe 25584
pid=25584
exename=C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2410.21.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe
hWnd className / caption
---------- ---------------------------------------------
0x00090d9a Notepad / タイトルなし - メモ帳
0x00040dd4 MSCTFIME UI / MSCTFIME UI
0x000302f4 IME / Default IME
0x00050d8c MSCTFIME UI / MSCTFIME UI
0x00150af2 IME / Default IME
---------- ---------------------------------------------
コメント