続いては、
- モジュール名が指定された文字列を含んでいれば
- 子ウインドウを列挙する
- さらに、ListViewかどうかも判定する
という処理を加えます。イベントハンドラー(コールバック関数)に渡したいパラメーターが「指定された文字列」と「モジュール名を取得する関数」の2つになってしまったので、適当に構造体を作ることにします。
あと、Cygwinにはstrcasestr()がないので、一度全部小文字に変換しています。まあこの辺は適当に・・・。
パラメーターを構造体にしたおかげで、関数ポインターをキャストするところがLispみたいに括弧だらけになってしまった。まあその辺も気にしない。
#include <stdio.h> #include <ctype.h> #include <windows.h> #include <commctrl.h> #define BUFSIZE 128 #define DEFAULT_MODULE "Explorer.EXE" typedef struct _callback_args{ void *fp; char module_name[BUFSIZE]; } callback_args; BOOL CALLBACK EnumWindowsProc(HWND, LPARAM); BOOL CALLBACK EnumChildProc(HWND, LPARAM); void tolower_str(char *); int main(int argc, char **argv){ HINSTANCE hInstpsapi; callback_args cba; if(argc > 1){ strncpy(cba.module_name, argv[1], BUFSIZE); } else{ strncpy(cba.module_name, DEFAULT_MODULE, BUFSIZE); } tolower_str(cba.module_name); if((hInstpsapi = LoadLibrary("psapi.dll")) == NULL){ return -1; } if((cba.fp = GetProcAddress(hInstpsapi, "GetModuleBaseNameA")) == NULL){ return -1; } EnumWindows(EnumWindowsProc, (LPARAM)&cba); FreeLibrary(hInstpsapi); return 0; } BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { char title[BUFSIZE], modulename[BUFSIZE]; DWORD pid; HANDLE hProc; DWORD (WINAPI *fpGetModuleBaseName)(HANDLE, HMODULE, LPTSTR, DWORD) = (DWORD (WINAPI *)(HANDLE, HMODULE, LPTSTR, DWORD))(((callback_args *)lParam)->fp); GetWindowThreadProcessId(hWnd, &pid); if(!(hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid))){ return 2; } fpGetModuleBaseName(hProc, NULL, modulename, BUFSIZE); tolower_str(modulename); GetWindowText(hWnd, title, BUFSIZE); printf("%08X, %s, %s\n", (unsigned)hWnd, modulename, title); if(strstr(modulename, ((callback_args *)lParam)->module_name) != NULL){ EnumChildWindows(hWnd, EnumChildProc, lParam); } return 1; } BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam) { char classname[BUFSIZE]; GetClassName(hWnd, classname, BUFSIZE); printf(" %08X, %s\n", (unsigned)hWnd, classname); if(strstr(classname, WC_LISTVIEW) != NULL){ printf(" => %s is ListView (%d items)\n", classname, ListView_GetItemCount(hWnd)); } return 1; } /* lower string */ void tolower_str(char *s) { char *p; for (p=s; *p; p++){ *p = tolower(*p); } }
適当に書いたわりには動いてしまってびっくり。Windows APIは面白いなあ。思ったんだけど、これって簡易psとして使えるよなあ。PIDがウインドウハンドルで。killしたいときはウインドウハンドルにWM_CLOSE(だっけ?)とか送りつければいいし。Unix系(POSIX?)のシグナルよりもいろんなことができるので、面白い。
いよいよ次回は http://www.yoshibaworks.com/ayacy/inasoft/lv2csv/lvcsvcom/chapter3.html に書かれている、他のプロセスのメモリーを読み書きする処理にいくよ!これを見ると、さすがにWindowsすげーって思わざるを得ないね。そんなことできるのかよ!って。