遍历Windows桌面上所有窗口

引言

昨日lexli在工作中遇到这样一个问题:一款性能测试软件需要知道桌面上窗口的Title,同时需要知道软件启动后Title分别被设置了几次,设置的title分别对应什么。通常我们可以直接查看窗口的缩略图,得到对应的标题。但是,对于软件启动后设置了多少次title以及每次title分别被设置为什么,这个问题突然感到无从下手。不过幸好公司有熟悉windows编程的高手,稍微一点拨知道原来可以通过windows API获得这些相关信息。下面,将自己经过点拨后的思路记录下来,方便以后不定期回顾。

需求分析

这里,通过对原来问题进行分解,可以将这个问题抽象为这样两个步骤:
* 遍历当前桌面上的所有窗口,得到每一个窗口的HWND
* 根据遍历到的窗口HWND,获取窗口的Title以及ClassName
而这两个步骤正好对应了相关的windows API.他们分别是:
EnumWindows
EnumChildWindows
GetWindowText
GetClassName
这里分别介绍下上面四个API:EnumWindows可以遍历当前屏幕上所有的父窗口(带有WS_CHILD属性风格);EnumChildWindows配合EnumWindows,可以遍历父窗口下所有的子窗口(以及子窗口的子窗口,会进行递归查找);GetWindowText可以通过遍历到的HWND得到对应window的Title;GetClassName则通过遍历得到的HWND获取对应Window的Class属性。了解了上述API属性后,我们就可以编写相关代码来进行验证了。

代码验证

按照上文提出的需求分解,我们将首先实现第一个步骤:得到每一个窗口的HWND。

#include <iostream>
#include <Windows.h>

using namespace std;

BOOL CALLBACK EnumChildProc(_In_ HWND   hwnd, _In_ LPARAM lParam)
{
    cout << "[Child window] window handle: " << hwnd << endl;

    return TRUE;
}


BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{

    /*
     * Remarks
        The EnumWindows function does not enumerate child windows, 
        with the exception of a few top-level windows owned by the 
        system that have the WS_CHILD style.
     */
    cout << "[Parent window] window handle: " << hwnd << endl;
    EnumChildWindows(hwnd, EnumChildProc, lParam);

    return TRUE;
}


int main(int argc, char *argv[])
{
    EnumWindows(EnumWindowsProc, 0);
    return 0;
}

注意 回调函数的返回值必须为TRUE才能保证系统会依次遍历每一个窗口。如果返回值非TRUE,则在当前窗口后不会进行后续的遍历动作。

在得到了所有窗口的HWND后,获取Title和ClassName就太简单了,直接用窗口的HWND + API去获取。这样,整个需求的完整实现如下:

#include <iostream>
#include <Windows.h>

using namespace std;

BOOL CALLBACK EnumChildProc(_In_ HWND   hwnd, _In_ LPARAM lParam)
{
    char szTitle[MAX_PATH] = {0};
    char szClass[MAX_PATH] = {0};
    int nMaxCount = MAX_PATH;

    LPSTR lpClassName = szClass;
    LPSTR lpWindowName = szTitle;

    GetWindowTextA(hwnd, lpWindowName, nMaxCount);
    GetClassNameA(hwnd, lpClassName, nMaxCount);
    cout << "[Child window] window handle: " << hwnd << " window name: " 
        << lpWindowName << " class name " << lpClassName << endl; 

    return TRUE;
}


BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{

    /*
     * Remarks
        The EnumWindows function does not enumerate child windows, 
        with the exception of a few top-level windows owned by the 
        system that have the WS_CHILD style.
     */
    char szTitle[MAX_PATH] = {0};
    char szClass[MAX_PATH] = {0};
    int nMaxCount = MAX_PATH;

    LPSTR lpClassName = szClass;
    LPSTR lpWindowName = szTitle;

    GetWindowTextA(hwnd, lpWindowName, nMaxCount);
    GetClassNameA(hwnd, lpClassName, nMaxCount);
    cout << "[Parent window] window handle: " << hwnd << " window name: " 
        << lpWindowName << " class name " << lpClassName << endl; 

    EnumChildWindows(hwnd, EnumChildProc, lParam);

    return TRUE;
}


int main(int argc, char *argv[])
{
    EnumWindows(EnumWindowsProc, 0);
    return 0;
} 

结论

  1. EnumWindows API是实现该需求的核心,需要了解其含义
  2. GetWindowText以及GetClassName都是可以查MSDN得到了
  3. 最重要的一点:对于自己不熟悉的领域,多交流,别人的一句点拨可以是你少走太多的弯路。
    原文作者:csdn_lexli
    原文地址: https://blog.csdn.net/csdn_lexli/article/details/51205220
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞