pythonwindowsscreenshotvideo-recording

How to get all the visible windows in python?


The main goal of my project is to take a screenshot of a specific application.

The steps that i need to perform are the following:

  1. List all the visible windows with relative title and pid

  2. The user enter in input the pid of the window choosen

  3. The program gets the coordinates of the window by using the pid and than take a screenshot.

In order to get all the visible windows I'm using the following function

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

The problem are two:

  1. The windows returned are more than expected, for example the "NVIDIA GeForce Overlay" window has the "WS_VISIBLE" attribute but in reality it is invisible.

  2. The pid associated with some windows is wrong and it refers to "ApplicationFrameHost.exe". I checked in the task manager and the correct pid is associated with another process of the same program but that does not have the "WS_VISIBLE" attribute.

I need something that substitute IsWindowVisible() in order to filter all the windows.

A partial solution for the point number 2 could be to find the PID of "ApplicationFrameHost.exe" and filter all the windows eliminating those with that PID but this will solve only a part of the second problem.


Solution

  • After more researches I finally found the solution to the first point thanks to this post: Filtering Background Processes PyWin32

    The final code is the following:

    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
    

    While for the second problem I solved by using the "hwnd" instead of the pid.