Get the title of a window of another program using the process name
Question: This question is probably quite basic but I'm having difficulty cracking it. I
assume that I will have to use something in `ctypes.windll.user32`. Bear in
mind that I have little to no experience using these libraries or even
`ctypes` as a whole.

I have used this code to list all the window titles, but I have no idea how I
am supposed to change this code to get a window title with a process name:

    
    
    import ctypes
    
    EnumWindows = ctypes.windll.user32.EnumWindows
    EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
    GetWindowText = ctypes.windll.user32.GetWindowTextW
    GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
    IsWindowVisible = ctypes.windll.user32.IsWindowVisible
    
    titles = []
    def foreach_window(hwnd, lParam):
        if IsWindowVisible(hwnd):
            length = GetWindowTextLength(hwnd)
            buff = ctypes.create_unicode_buffer(length + 1)
            GetWindowText(hwnd, buff, length + 1)
            titles.append(buff.value)
        return True
    EnumWindows(EnumWindowsProc(foreach_window), 0)
    
    print(titles)
    

This code is from <https://sjohannes.wordpress.com/2012/03/23/win32-python-
getting-all-window-titles/>

If my question is unclear, I would like to achieve something like this (just
an example - I'm not asking specifically about Spotify):

    
    
    getTitleOfWindowbyProcessName("spotify.exe") // returns "Avicii - Waiting For Love" (or whatever the title is)
    

A complication that may arise, if there are multiple windows running with the
same process name (e.g. multiple chrome windows)

Thank you.

* * *

**EDIT** : To clarify, I want some code that takes a process name and returns
a (possibly empty) list of window titles owned by that process as strings.


Answer: Here's what I meant in the comment:

    
    
    import win32gui
    def enumWindowsProc(hwnd, lParam):
        print win32gui.GetWindowText(hwnd)
    win32gui.EnumWindows(enumWindowsProc, 0)
    

Below, I pasted the whole thing...it doesn't work on the PC that I am at right
now, since I messed up with security settings(it's an XP!!!) and I get a bunch
of _Access denied_ (error code: **5**) errors, but here it is:

    
    
    import sys
    import os
    import traceback
    import ctypes
    from ctypes import wintypes
    import win32con
    import win32api
    import win32gui
    import win32process
    
    def enumWindowsProc(hwnd, lParam):
        if (lParam is None) or ((lParam is not None) and (win32process.GetWindowThreadProcessId(hwnd)[1] == lParam)):
            text = win32gui.GetWindowText(hwnd)
            if text:
                wStyle = win32api.GetWindowLong(hwnd, win32con.GWL_STYLE)
                if wStyle & win32con.WS_VISIBLE:
                    print("%08X - %s" % (hwnd, text))
    
    def enumProcWnds(pid=None):
        win32gui.EnumWindows(enumWindowsProc, pid)
    
    def enumProcs(procName=None):
        pids = win32process.EnumProcesses()
        if procName is not None:
            bufLen = 0x100
            bytes = wintypes.DWORD(bufLen)
            _OpenProcess = ctypes.cdll.kernel32.OpenProcess
            _GetProcessImageFileName = ctypes.cdll.psapi.GetProcessImageFileNameA
            _CloseHandle = ctypes.cdll.kernel32.CloseHandle
            filteredPids = ()
            for pid in pids:
                try:
                    hProc = _OpenProcess(wintypes.DWORD(win32con.PROCESS_ALL_ACCESS), ctypes.c_int(0), wintypes.DWORD(pid))
                except:
                    print("Process [%d] couldn't be opened: %s" % (pid, traceback.format_exc()))
                    continue
                try:
                    buf = ctypes.create_string_buffer(bufLen)
                    _GetProcessImageFileName(hProc, ctypes.pointer(buf), ctypes.pointer(bytes))
                    if buf.value:
                        name = buf.value.decode().split(os.path.sep)[-1]
                        #print name
                    else:
                        _CloseHandle(hProc)
                        continue
                except:
                    print("Error getting process name: %s" % traceback.format_exc())
                    _CloseHandle(hProc)
                    continue
                if name.lower() == procName.lower():
                    filteredPids += (pid,)
            return filteredPids
        else:
            return pids
    
    def main(args):
        if args:
            procName = args[0]
        else:
            procName = None
        pids = enumProcs(procName)
        print(pids)
        for pid in pids:
            enumProcWnds(pid)
    
    if __name__ == "__main__":
        main(sys.argv[1:])
    

Needless to say that:

  * In order for this code to work you need to run it as a privileged user (Administrator); at least [SeDebugPrivilege](https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716\(v=vs.85\).aspx) is required.
  * There might be surprises when the processes are running in 32/64 bit modes (the `python` process that you execute this code from, and the target processes enumerated by the code)

