如何获取python中所有可见的windows?

How to get all the visible windows in python?

我项目的主要目标是截取特定应用程序的屏幕截图。

我需要执行的步骤如下:

  1. 列出所有可见的 windows 以及相对标题和 pid

  2. 用户输入window选择的pid

  3. 程序通过pid获取window的坐标,然后截图。

为了获得所有可见的 windows 我正在使用以下函数

from sys import platform as sys_platform
if sys_platform == 'win32':
    from win32gui import EnumWindows, GetWindowText, IsWindowVisible, IsIconic
    from win32process import GetWindowThreadProcessId

def get_visible_windows():
    if sys_platform == 'win32':
        visible_windows = []
        def callback(hwnd, _):
            if IsWindowVisible(hwnd) and not IsIconic(hwnd):
                _, cpid = GetWindowThreadProcessId(hwnd)
                title = GetWindowText(hwnd)
                if title != '':
                    visible_windows.append({'Title' : title, 'Pid' : cpid})
        EnumWindows(callback, None)
        return visible_windows

问题有两个:

  1. 返回的windows超出预期,例如“NVIDIA GeForce Overlay”window具有“WS_VISIBLE”属性,但实际上是看不见。

  2. 与某些windows关联的pid是错误的,它指的是“ApplicationFrameHost.exe”。我检查了任务管理器,正确的 pid 与同一程序的另一个进程相关联,但没有“WS_VISIBLE”属性。

我需要一些东西来替代 IsWindowVisible() 以过滤所有 windows。

点号 2 的部分解决方案可能是找到“ApplicationFrameHost.exe”的 PID 并过滤掉所有 windows 消除具有该 PID 的那些,但这只会解决一部分第二个问题。

经过更多的研究,我终于找到了第一点的解决方案,多亏了这个post:

最终代码如下:

def get_visible_windows():
    if sys_platform == 'win32':
        class TITLEBARINFO(ctypes.Structure):
            _fields_ = [("cbSize", ctypes.wintypes.DWORD), ("rcTitleBar", ctypes.wintypes.RECT),
                    ("rgstate", ctypes.wintypes.DWORD * 6)]
        visible_windows = []
        def callback(hwnd, _):
            # Title Info Initialization
            title_info = TITLEBARINFO()
            title_info.cbSize = ctypes.sizeof(title_info)
            ctypes.windll.user32.GetTitleBarInfo(hwnd, ctypes.byref(title_info))

            # DWM Cloaked Check
            isCloaked = ctypes.c_int(0)
            ctypes.WinDLL("dwmapi").DwmGetWindowAttribute(hwnd, 14, ctypes.byref(isCloaked), ctypes.sizeof(isCloaked))

            # Variables
            title = GetWindowText(hwnd)

            # Append HWND to list
            if not IsIconic(hwnd) and IsWindowVisible(hwnd) and title != '' and isCloaked.value == 0:
                if not (title_info.rgstate[0] & STATE_SYSTEM_INVISIBLE):
                    _, cpid = GetWindowThreadProcessId(hwnd)
                    visible_windows.append({'title' : title, 'pid' : cpid, 'hwnd' : hwnd})
        EnumWindows(callback, None)
        return visible_windows
    elif sys_platform == 'linux':
        return

而对于第二个问题,我使用“hwnd”而不是 pid 解决了。