Search code examples
pythonwinapipywin32

Filtering Background Processes PyWin32


I have been working on filtering out windows out of EnumWindows from only including windows that are minimized or open to a list.

Code

def winEnumHandler(hwnd, ctx):
    title = win32gui.GetWindowText(hwnd)

    # Append HWND to list
    if win32gui.IsWindowVisible(hwnd) and title != '':
        app = ApplicationWindow(hwnd, title)
        applications.append(app)


def scanApplication():
    applications.clear()
    win32gui.EnumWindows(winEnumHandler, None)
    return applications

Expected/Actual

The problem with this code is that it does not correctly filter out some windows that are found through the EnumWindows For example currently I have: Chrome ,IDE, and Discord open on my computer and only expect these to be in the applications list. However, I not only get those windows but background tasks such as: Calculator, Mail, Geforce Overlay, etc... These Background tasks are active but there is no window on the desktop nor are any of these minimzed. How would I be able to filter out background tasks out of EnumWindows? Thanks for reading!


Solution

  • After doing some more research I ran into DWM, DWM offers a way you can look up attributes of windows to get more information out of them. One of these options is called cloak and does a great job at filtering out background processes from all windows. My code for this is below. I will also link the stackoverflow post that talks about DWMA in more detail.

    def winEnumHandler(hwnd, ctx):
        # DWM
        isCloacked = ctypes.c_int(0)
        ctypes.WinDLL("dwmapi").DwmGetWindowAttribute(hwnd, 14, ctypes.byref(isCloacked), ctypes.sizeof(isCloacked))
    
        # Variables
        title = win32gui.GetWindowText(hwnd)
    
        # Append HWND to list
        if win32gui.IsWindowVisible(hwnd) and title != '' and isCloacked.value == 0:
            app = ApplicationWindow(hwnd, title)
            applications.append(app)
    

    DWM Filtering: Here

    Following more from that link this final solution showed all the real windows:

    class TITLEBARINFO(ctypes.Structure):
        _fields_ = [("cbSize", ctypes.wintypes.DWORD), ("rcTitleBar", ctypes.wintypes.RECT),
                    ("rgstate", ctypes.wintypes.DWORD * 6)]
    
    
    def winEnumHandler(hwnd, ctx):
        # 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 = wg.GetWindowText(hwnd)
    
        # Append HWND to list
        if wg.IsWindowVisible(hwnd) and title != '' and isCloaked.value == 0:
            if not (title_info.rgstate[0] & wc.STATE_SYSTEM_INVISIBLE):
                app = ApplicationWindow(hwnd, title)
                applications.append(app)
    

    Any simplifications please let me know! Thanks!