如何获取python中所有可见的windows?
How to get all the visible windows in python?
我项目的主要目标是截取特定应用程序的屏幕截图。
我需要执行的步骤如下:
列出所有可见的 windows 以及相对标题和 pid
用户输入window选择的pid
程序通过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
问题有两个:
返回的windows超出预期,例如“NVIDIA GeForce Overlay”window具有“WS_VISIBLE”属性,但实际上是看不见。
与某些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 解决了。
我项目的主要目标是截取特定应用程序的屏幕截图。
我需要执行的步骤如下:
列出所有可见的 windows 以及相对标题和 pid
用户输入window选择的pid
程序通过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
问题有两个:
返回的windows超出预期,例如“NVIDIA GeForce Overlay”window具有“WS_VISIBLE”属性,但实际上是看不见。
与某些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 解决了。