【Demo 0032】遍历子窗体
在上节中我们学习如何遍历顶层窗体,本节中我们继续学习如何遍历子窗体,在例程中我们用使用了二种方法来遍历子窗体;
1. 使用EnumChildWindows 遍历
BOOL EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc, LPARAM lParam );
功能: 遍历指定窗体的子窗体,将遍历到的子窗体通知预设的回调函数,并以遍历完子窗体或回调函数返回FALSE结束, 最后一参数用于将信息传递给回调函数
说明: a. 与函数与EnumChildWindows函数用法与EnumWindows几乎一样, EnumWindows 仅能遍历顶层窗体; 此函数枚举的窗体为CreateWindowEx时风格设有WS_CHILD
且父窗体被指定为EnumChildWindows中第一个参数
b. EnumChildWindows 不能枚举到遍历前己销毁和遍历期间己创建的窗体
2. 使用GetWindow 遍历
HWND GetWindow(HWND hWnd, UINT uCmd);
功能: 获取与指定窗体相对关系(Z-ORDER,OWNER), 根据uCmd参数不同返回不同的窗体
GW_CHILD 返回hWnd窗体第一个子窗体
GW_ENABLEDPOPUP
GW_HWNDFIRST 返回与hWnd窗体具有相同z-oder的窗体
GW_HWNDLAST 意思与GW_HWNDFIRST 相同, 仅表示返回的是最后一个
GW_HWNDNEXT 通常与GW_HWNDFIRST配合使用返回下一个具有相同z-oder的窗体
GW_HWNDPREV 通常与GW_HWNDLAST配合使用返回上一个具有相同z-oder的窗体
GW_OWNER 获取指定窗体拥有者窗体或父窗体
说明: 此方法遍历子窗体没有EnumChildWindows函数稳定, 但它可以枚举到遍历期间消毁的窗体.
我们例程功能主要演示了这两种遍历方法的使用, 演示过程中我们将遍历到的窗体分别显示到二个ListBox窗体中, 看看演示代码
1. 调用方法
- case WM_COMMAND:
- {
- switch (wParam)
- {
- case IDC_BTNDATAREAD:
- {
- HWND hListbox = GetDlgItem(hWnd, IDC_LSTWNDLIST);
- HWND hListbox1 = GetDlgItem(hWnd, IDC_LSTWNDLIST1);
- SendMessage(hListbox, LB_RESETCONTENT, 0, 0);
- SendMessage(hListbox1, LB_RESETCONTENT, 0, 0);
- HWND hParent = GetDesktopWindow();
- _EnumChildWindows(hParent, hListbox);
- EnumChildWindows(hParent, EnumChildWndProc, (LPARAM)hListbox1);
- SetWindowText(GetDlgItem(hWnd, IDC_BTNDATAREAD), _T("Refresh"));
- }
- break;
- }
- break;
- }
2. _EnumChildWindows - GetWindow方法遍历
- //////////////////////////////////////////////////////////////////////////
- void _EnumChildWindows(HWND hParent, HWND hDisplay)
- {
- HWND hWndChild = GetWindow(hParent, GW_CHILD);
- HWND hWndTemp = GetWindow(hWndChild, GW_HWNDFIRST);
- do {
- TCHAR szWndInfo[512] = {0};
- TCHAR szWndTitle[256] = {0};
- TCHAR szClsName[64] = {0};
- GetWindowText(hWndTemp, szWndTitle, 256);
- GetClassName(hWndTemp, szClsName, 64);
- _stprintf(szWndInfo,
- _T("´°¿Ú%08X ")
- _T("\"%s\"")
- _T("%s ")
- _T("%s"),
- hWndTemp,
- szWndTitle,
- szClsName,
- IsWindowVisible(hWndTemp) ? _T("Visible") : _T("Invisible"));
- SendMessage(hDisplay, LB_ADDSTRING, 0, (LPARAM)szWndInfo);
- } while (NULL != (hWndTemp = GetWindow(hWndTemp, GW_HWNDNEXT)));
- }
3. EnumChildWindows 方法
- //////////////////////////////////////////////////////////////////////////
- BOOL CALLBACK EnumChildWndProc(HWND hWnd, LPARAM lParam)
- {
- HWND hListbox = (HWND)lParam;
- if (NULL == hWnd) return FALSE;
- if (NULL != hListbox && IsWindow(hListbox))
- {
- TCHAR szWndInfo[512] = {0};
- TCHAR szWndTitle[256] = {0};
- TCHAR szClsName[64] = {0};
- GetWindowText(hWnd, szWndTitle, 256);
- GetClassName(hWnd, szClsName, 64);
- _stprintf(szWndInfo,
- _T("´°¿Ú%08X ")
- _T("\"%s\" ")
- _T("%s ")
- _T("%s"),
- hWnd,
- szWndTitle,
- szClsName,
- IsWindowVisible(hWnd) ? _T("Visible") : _T("Invisible"));
- SendMessage(hListbox, LB_ADDSTRING, 0, (LPARAM)szWndInfo);
- }
- return TRUE;
- }
遍历结果图, 我也参考了SPY++ 的遍历方法
根据上图的结果我发现两个问题, 1. 使用GetWindow与EnumChildWindows枚举出来的窗体不一致; 2. SPY++ 遍历的结果与通过GetWindow的得到的结果是一样的,说明SPY++也是使用了这种方式.