Search code examples
pythonwindowspywin32

windows executables corresponding to system tray icons?


Is there a way to use Python to get a list of all the icons in the system tray (lower right hand corner) and their associated processes and executables?

Here is a thread on how to do this using AHK:

http://www.autohotkey.com/forum/topic17314.html

but it relies heavily on AHK.

Note that I'm interested this for in Windows XP/7

Thanks!


Solution

  • This is thick, thick win32 stuff. I started writing this using pywin32 but switched over to ctypes to better deal with the structures. Note, I wrote this in 32 win XP. You'll have the change the TBBUTTON def for 64 bit. I am not sure what UAC will do to this (can you allocate memory in another process?).

    import commctrl, win32con
    from ctypes import *
    
    # represent the TBBUTTON structure
    # note this is 32 bit, 64 bit padds 4 more reserved bytes
    class TBBUTTON(Structure):
        _pack_ = 1
        _fields_ = [
            ('iBitmap', c_int),
            ('idCommand', c_int),
            ('fsState', c_ubyte),
            ('fsStyle', c_ubyte),
            ('bReserved', c_ubyte * 2),
            ('dwData', c_ulong),
            ('iString', c_int),
        ]
    
    # get the handle to the sytem tray
    hWnd = windll.user32.FindWindowA("Shell_TrayWnd", None)
    hWnd = windll.user32.FindWindowExA(hWnd, None, "TrayNotifyWnd", None)
    hWnd = windll.user32.FindWindowExA(hWnd, None, "SysPager", None)
    hWnd = windll.user32.FindWindowExA(hWnd, None, "ToolbarWindow32", None)
    
    # get the count of icons in the tray
    numIcons = windll.user32.SendMessageA(hWnd, commctrl.TB_BUTTONCOUNT, 0, 0)
    
    # allocate memory within the system tray
    pid = c_ulong();
    windll.user32.GetWindowThreadProcessId(hWnd, byref(pid))
    hProcess = windll.kernel32.OpenProcess(win32con.PROCESS_ALL_ACCESS, 0, pid)
    lpPointer = windll.kernel32.VirtualAllocEx(hProcess, 0, sizeof(TBBUTTON), win32con.MEM_COMMIT, win32con.PAGE_READWRITE)
    
    # init our tool bar button and a handle to it
    tbButton = TBBUTTON()
    butHandle = c_int()
    
    for i in range(numIcons):
        # query the button into the memory we allocated
        windll.user32.SendMessageA(hWnd, commctrl.TB_GETBUTTON, i, lpPointer)
        # read the memory into our button struct
        windll.kernel32.ReadProcessMemory(hProcess, lpPointer, addressof(tbButton), 20, None)
        # read the 1st 4 bytes from the dwData into the butHandle var
        # these first 4 bytes contain the handle to the button
        windll.kernel32.ReadProcessMemory(hProcess, tbButton.dwData, addressof(butHandle), 4, None)
    
        # get the pid that created the button
        butPid = c_ulong()
        windll.user32.GetWindowThreadProcessId(butHandle, byref(butPid))
    
        # i leave it to you to get the process from the pid
        # that should be trivial...
        print butPid