【Demo 0031】遍历顶层窗体

今天我们将讲述如何遍历系统中所有的顶层窗体,讲述之前我们提个问题, 什么是顶层窗体, 顶层窗体有些什么特点呢?  我引用了Codeguru上的老外的描述看看他是怎么说的:

 

Q: What is a top-level window?

A: A top-level window is a window that is not child, i.e. it has not WS_CHILD style set.

Notes
unlike the child windows, a top-level window can be displayed anywhere in the screen;
many definitions state that a top-level window is "a window that has no parent"; 
that is correct but can lead in a confusion: many people think that every window which is created passing a valid hWndParent in CreateWindow(Ex) "has a parent" then, according to the definition it is not top-level; 
in fact hWndParent may be either a handle to parent or owner window; 
if hWndParent is a valid window handle and WS_CHILD style is not set, then we have a top-level owned window;
a top-level window can or can not be owned but is never a child; further we can say that it can have an owner but never has a parent.
top-level windows can be either overlapped windows (having WS_OVERLAPPED style and generally used as application main window) or popup windows (having WS_POPUP style, usually temporary windows like message boxes and dialogs);
the coordinates used in CreateWindow(Ex), MoveWindow, SetWindowPos, and so on are always scren coordinates (relative to top-left corner of the screen).

Examples
Code:
// create a top-level window (not owned)
HWND hWnd = CreateWindow(szWindowClass, szTitle, 
              WS_OVERLAPPED, // WS_CHILD style is not set, so it's a top-level window.
              CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 
              NULL,          // no handle to the owner, so it's not owned.
              NULL, hInstance, NULL);
Code:
// create a top-level window (owned)
HWND hWnd = CreateWindow(szWindowClass, szTitle, 
              WS_OVERLAPPED, // WS_CHILD style is not set, so it's a top-level window
              CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 
              hWndParent,    // handle to the owner, so it's an owned window
              NULL, hInstance, NULL);

正如上文所说, 顶层窗体就是不具体WS_CHILD风格的窗体它可以在屏幕上任务拖动, 从文中还加深对CreateWindow 中HWNDPARENT参数的理解,它在风格不为WS_CHILD时,这个Parent 不是父窗体而是拥有者窗体, 同时也让我明白怎么样的窗体是拥有者窗体 (有学到新东西,  心情爽极了! ^_^),  再引用一下什么时拥有者窗体:

Q: What is an owned window?

A: An owned window is a top-level window that has an owner.
It has the following properties:
being a top-level window, it can be displayed anywhere in the screen;
it stays always in the front of its owner window;
it is hidded when its owner is hidden or minimized;
it is destroyed when its owner is being destroyed;
Notes
An owned window is created by passing the owner window handle as hWndParent parameter in CreateWindow(Ex) function call.
WS_CHILD style must not be set, otherwise results a child and not an owned top-level window.

Example
Code:
// create an owned top-level window
HWND hWnd = CreateWindow(szWindowClass, szTitle, 
              WS_OVERLAPPED, // WS_CHILD style is not set
              CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 
              hWndParent,    // handle to the OWNER window
              NULL, hInstance, NULL);

有了对上文的讲述, 我们对下面的内容就好理解多了, 通常顶层窗体都是应用窗体的主窗体,可用这个方法找到系统中运行的应用程序(有UI的), 系统为达到此目的提供对应的函数:
一、函数声明

BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
功能: 遍历屏幕中所有的顶层窗体,并通过预定的回调函数返回遍历到窗体的句柄直到遍历结束或回调函数返回FALSE

      回调函数类型:  typedef BOOL (CALLBACK* WNDENUMPROC)(HWND, LPARAM);

二、代码演示

     1.  设置遍历顶层窗体的回调函数,并将ListBox控件做为参数->(我们通过一个ListBox将顶层窗体信息显示出来)

EnumWindows(EnumWndProc, (LPARAM)GetDlgItem(hWnd, IDC_LSTWNDLIST));
SetWindowText(GetDlgItem(hWnd, IDC_BTNDATAREAD), _T("Refresh"));

    2.  遍历到顶层窗体后


//////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumWndProc(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"),
                  hWnd,
                  szWndTitle,
                  szClsName);
        SendMessage(hListbox, LB_ADDSTRING, 0, (LPARAM)szWndInfo);
    }

    return TRUE;
}

    备注:  若我们要提前退出遍历函数,可将此回调函数返加值设为FALSE即可提前结束遍历;

演示代码

原文地址:https://www.cnblogs.com/ztercel/p/2150012.html