「プロセスIDなら分かるけど、ウィンドウハンドルが分からない」「実行ファイル名なら分かる」「実行ファイルのタイトル名なら分かる」など色々な状況があると思います。
スポンサードリンク
Windows パソコン上で gnupack_devel(cygwin) を利用して動作確認しています。
VC++等を使わず、windowsアプリケーションを開発する事を前提としています。
mingwはgccコンパイラです。gnupack_devel(cygwin) 利用者はmingw64-i686-gcc-coreを次のようにインストールします。
apt-cyg install mingw64-i686-gcc-core
もしくはインストーラーをダウンロードしてきて設定を行います。
ダウロードしてインストールを開始します。
「MinGW Installation Manager」を開き、次の項目にチェック(Mark for Installation)しましょう。
インストール後には、環境変数にパス設定が必要です。
Windowsの環境変数に設定する場合には、変数名に「PATH」、変数値に「C:\MinGW\bin;C:\MinGW\msys\1.0\bin」のように記述します。
gnupack_devel(cygwin)で行う場合は次のようになります。
export PATH="/c/MinGW/bin:/c/MinGW/msys/1.0/bin":$PATH
説明するために各部分を切り分けています。
#include#include #include #include
PSAPIは、ウィンドウズでプロセス情報の取得を行うプログラムを書くためのAPIです。
まず、コードの中でpsapi.hをincludeしなくてはなりません。
HWND GetWindowHandleByPID(const DWORD targetPID) { HWND hWnd = GetTopWindow(NULL); do { if (GetWindowLong( hWnd, GWL_HWNDPARENT) != 0 || !IsWindowVisible( hWnd)) { continue; } DWORD getPID; GetWindowThreadProcessId( hWnd, &getPID); if (targetPID == getPID) { return hWnd; } } while((hWnd = GetNextWindow( hWnd, GW_HWNDNEXT)) != NULL); return NULL; }
次のような実装になっています。
このため、トップレベルウィンドウ(親ウィンドウがない普通のウィンドウ)が、複数あるようなアプリケーションでは、Zオーダーが上のウィンドウ(より前面にあるウィンドウ)が返されます。
要するに、1つのプロセスで複数のウィンドウが開くアプリケーションに対して実行する場合は注意してください。
HWND GetWindowHandleByName(const char exeName[]) { DWORD allProc[1024]; DWORD cbNeeded; int nProc; int i; // PID一覧を取得 if (!EnumProcesses(allProc, sizeof(allProc), &cbNeeded)) { return NULL; } nProc = cbNeeded / sizeof(DWORD); for (i = 0; i < nProc; i++) { char procName[MAX_PATH] = TEXT(""); HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, allProc[i]); // プロセス名を取得 if (NULL != hProcess) { HMODULE hMod; DWORD cbNeeded; if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { GetModuleBaseName(hProcess, hMod, procName, sizeof(procName)/sizeof(TCHAR)); } } if (!lstrcmpi(procName, exeName)) { return GetWindowHandleByPID(allProc[i]); } CloseHandle(hProcess); } return NULL; }
32 ビットのアプリケーションで GetModuleFileNameEx 関数を使用した場合、64 ビットのアプリケーションが生成したプロセスを起動した実行パス名は検出できません。
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int showCmd) { RECT lprc; HWND hWnd = GetWindowHandleByName("WinSCP.exe"); if (hWnd == NULL) { MessageBox(NULL, "実行ファイルは起動していません", "メッセージ", MB_OK); return -1; } GetWindowRect( hWnd, &lprc ); printf("left = %ld\n", lprc.left); printf("top = %ld\n", lprc.top); return 0; }
起動していることを確認するために参考として、GetWindowRect() を利用して、指定したウインドウの左上端の座標を出力しています。
なお、ヘッダファイル「windows.h」をインクルードするエントリポイントは、main関数ではなく「WinMain関数」となります。
g++ -Wall -O3 -o getwindowhandle.o -c getwindowhandle.c g++ getwindowhandle.o -lpsapi -static-libgcc -static-libstdc++ -o getwindowhandle.exe
リンカ対応として、psapi.lib(またはpsapi.dll)のライブラリファイルがリンクできるようにする必要があります。
その他の関係するGCCオプションは次のとおりです。
オプション | 説明 |
---|---|
-mno-cygwin | cygwin.dll がなくても起動できるようにする。gccが4.6以降はこのオプションはありません |
-mwindows | ウィンドウを伴うプログラム(無いとexe実行時にコマンドプロンプト表示) |
-static-libgcc | libgcc_s_dw2-1.dll を静的リンクする |
-static-libstdc++ | libstdc++-6.dll を静的リンクする |
cygwinのdllと一緒にコピーして使えばいいですが、GNUとかライセンスなどの配布条件があります。
libgcc_s_dw2-1.dll、libstdc++-6.dll のライブラリを静的リンク指定しています。指定しないと次のようなエラーが出力されます。
コンピュータに libgcc_s_dw2-1.dll がないため、プログラムを開始できません。この問題を解決するには、プログラムを再インストールしてみてください。
なお、Makefile を作成する場合は次のような記述になります。
SRC=getwindowhandle.c OBJS=$(SRC:.c=.o) PROG=getwindowhandle.exe CC=g++ CFLAGS=-Wall -O3 LIBS=-lpsapi -static-libgcc -static-libstdc++ RM=rm %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< .PHONY : all all: $(PROG) $(PROG): $(OBJS) $(CC) $(OBJS) $(LIBS) $(LDFLAGS) -o $@ .PHONY : clean clean: $(RM) $(OBJS)
スポンサードリンク
コンソール上から実行、もしくは実行ファイルのクリックで起動します。
$ getwindowhandle.exe ....(PID: 24312) mshta.exe (PID: 17540) chrome.exe (PID: 18876) chrome.exe (PID: 25484) WinSCP.exe (PID: 27516) left = 527 top = 135
スポンサードリンク