遍历所有顶层窗口
遍历窗口主要通过函数 EnumWindows 来实现,通过注册一个回调函数来获取窗口信息。
代码
WINDOWS_DATA_INFO 结构体:
typedef struct _WINDOWS_DATA_INFO
{
CString strTitleName; //窗口标题
int iWindowId; //窗口ID
int iProcessId; //窗口所属进程ID
}WINDOWS_DATA_INFO, *PWINDOWS_DATA_INFO;
调用 EnumWindows 函数:
BOOL GetWindowsInfo()
{
list<WINDOWS_DATA_INFO> listWindowInfo; //保存所有窗口信息
LPARAM param = reinterpret_cast<LPARAM>(&listWindowInfo);
if (!EnumWindows(WindwosEnumFun, param))
{
return FALSE;
}
return TRUE;
}
在 listWindowInfo 这个 List 中保存窗口信息。
EnumWindows 的回调函数:
BOOL CALLBACK WindwosEnumFun(HWND hwnd, LPARAM param)
{
do
{
list<WINDOWS_DATA_INFO>* pListWindowInfo = reinterpret_cast<list<WINDOWS_DATA_INFO>*>(param);
int iLen = GetWindowTextLength(hwnd); //窗口的标题文本字符长度
if (iLen == 0) //判断是否存在标题
{
break;
}
HWND owner = GetWindow(hwnd, GW_OWNER);
LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); //获取窗口样式
//判断窗口是否最小化
if (IsIconic(hwnd))
{
break;
}
//判断窗口可视状态
if (!IsWindowVisible(hwnd))
{
break;
}
//判断窗口风格
/*
if ((owner && !(exstyle & WS_EX_APPWINDOW)) || (exstyle & WS_EX_LAYERED))
{
break;
}
*/
const int iClassLength = 256;
WCHAR szClassName[iClassLength];
memset(szClassName, 0, iClassLength);
//获取指定窗口所属类名
int iClassNameLength = GetClassName(hwnd, szClassName, iClassLength);
//忽略掉任务管理器和开始按钮
if (wcscmp(szClassName, L"Progman") == 0 || wcscmp(szClassName, L"Button") == 0)
{
break;
}
//获取窗口标题
const int ITitleLength = 500;
WCHAR szTitleName[ITitleLength];
memset(szTitleName, 0, ITitleLength);
GetWindowText(hwnd, szTitleName, ITitleLength);
CString strTitleName = szTitleName;
if (strTitleName.IsEmpty())
{
break;
}
//通过窗口句柄获取进程ID
DWORD dwProcessId = 0;
GetWindowThreadProcessId(hwnd, &dwProcessId);
WINDOWS_DATA_INFO windowDataInfo;
windowDataInfo.strTitleName = strTitleName;
windowDataInfo.iProcessId = (int)dwProcessId;
windowDataInfo.iWindowId = (int)hwnd;
pListWindowInfo->push_back(windowDataInfo);
} while (FALSE);
return TRUE;
}
注:我将窗口的风格判断屏闭了,如果不屏蔽将获取不到 QQ 和微信的特殊风格的窗口。
如果要获取最顶层的出口只需要取 List 的第一个值即可。