バイト先で、アプリケーションごとにロジックを切り替えるシステムを作ることになった。
どうもネットで調べてすぐに分かるようなAPIだけでは、十分なウィンドウ選別ができないようで、三時間程度を試行錯誤だけで過ごしてしまった。
先輩に相談したところ、先輩はOBSのソースコードを辿り、あっという間に問題を解決した。
Windows10は、「電卓」や「設定」など幾つかのUWPアプリを待機させている。 このような待機中・バックグラウンドアプリを排除するために、ウィンドウがCloaked(隠されている)であるかを確認する必要があったようである。
尚、「電卓」や「設定」は、UWPアプリなるもので、元来のアプリとは異なる体系のアプリであるらしい。
流石は混沌のWindowsである。
WindowsやC言語に限らず、何事にも言える話であるが、後方互換性を気にするがあまりに混沌を極めるのは、非難されて然るべき状態である。
統括的な万能の道具は愚かである。
真に必要なのは、可用的な最小限の道具群である。
次の流れで実現できる。
ウィンドウアプリケーションのウィンドウタイトルを列挙するプログラムのソースコードを以下に示す。言語はC言語であり、一応GNU C Compilerを想定している。
#include <windows.h>
#include <dwmapi.h>
#include <stdio.h>
#include <string.h>
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lp) {
// skip invisible window
if (!IsWindowVisible(hWnd)) {
return TRUE;
}
// skip nameless window
CHAR title[256] = {};
int res_gwt = GetWindowTextA(hWnd, (LPSTR)title, 256);
if (!res_gwt || strlen(title) == 0) {
return TRUE;
}
// skip child window
DWORD styles = (DWORD)GetWindowLongPtrA(hWnd, GWL_STYLE);
if (styles & WS_CHILD) {
return TRUE;
}
// skip cloaked window
DWORD cloaked;
HRESULT res_dgwa = DwmGetWindowAttribute(hWnd, DWMWA_CLOAKED, &cloaked, sizeof(DWORD));
if (res_dgwa != S_OK || cloaked) {
return TRUE;
}
// skip Program Manager
CHAR classname[256] = {};
int res_gcn = GetClassName(hWnd, (LPSTR)classname, 256);
if (!res_gcn || strcmp(classname, "Progman") == 0) {
return TRUE;
}
// finish
printf("%s\n", title);
return TRUE;
}
int main() {
EnumWindows(EnumWindowsProc, (LPARAM)NULL);
return 0;
}
■