如何在python中获取系统托盘信息?

问题描述 投票:0回答:1

如何遍历系统托盘并获取其中的图标信息? 比如图标,创建它的过程...

我找到了一个满足我要求的page,我用Python正确地使用ctypes重写了它的代码。 原始代码基于Windows 10。

import ctypes
from ctypes import wintypes

# 定义常量
PROCESS_VM_OPERATION = 0x0008
PROCESS_VM_READ = 0x0010
PROCESS_VM_WRITE = 0x0020
MEM_COMMIT = 0x00001000
PAGE_EXECUTE_READWRITE = 0x40
MEM_RELEASE = 0x00008000
TB_BUTTONCOUNT = 0x0400 + 24
TB_GETBUTTON = 0x0417

# 定义结构体
class SYSTEM_INFO(ctypes.Structure):
    _fields_ = [
        ('wProcessorArchitecture', wintypes.WORD),
        ('wReserved', wintypes.WORD),
        ('dwPageSize', wintypes.DWORD),
        ('lpMinimumApplicationAddress', wintypes.LPVOID),
        ('lpMaximumApplicationAddress', wintypes.LPVOID),
        ('dwActiveProcessorMask', wintypes.DWORD),
        ('dwNumberOfProcessors', wintypes.DWORD),
        ('dwProcessorType', wintypes.DWORD),
        ('dwAllocationGranularity', wintypes.DWORD),
        ('wProcessorLevel', wintypes.WORD),
        ('wProcessorRevision', wintypes.WORD)
    ]

class TBBUTTON(ctypes.Structure):
    _fields_ = [
        ('iBitmap', ctypes.c_int),
        ('idCommand', ctypes.c_int),
        ('fsState', ctypes.c_byte),
        ('fsStyle', ctypes.c_byte),
        ('bReserved', ctypes.c_byte * 6),
        ('dwData', ctypes.c_void_p),
        ('iString', ctypes.c_void_p)
    ]

# 定义函数
def Is64bitSystem():
    si = SYSTEM_INFO()
    ctypes.windll.kernel32.GetNativeSystemInfo(ctypes.byref(si))
    return si.wProcessorArchitecture in [ctypes.wintypes.WORD(9), ctypes.wintypes.WORD(6)]

def FindTrayWnd():
    hWnd = ctypes.windll.user32.FindWindowW("Shell_TrayWnd", None)
    hWnd = ctypes.windll.user32.FindWindowExW(hWnd, None, "TrayNotifyWnd", None)
    hWnd = ctypes.windll.user32.FindWindowExW(hWnd, None, "SysPager", None)
    hWnd = ctypes.windll.user32.FindWindowExW(hWnd, None, "ToolbarWindow32", None)
    return hWnd

def FindNotifyIconOverflowWindow():
    hWnd = ctypes.windll.user32.FindWindowW("NotifyIconOverflowWindow", None)
    hWnd = ctypes.windll.user32.FindWindowExW(hWnd, None, "ToolbarWindow32", None)
    return hWnd

def EnumNotifyWindow(hWnd):
    # 获取托盘进程ID
    dwProcessId = wintypes.DWORD()
    ctypes.windll.user32.GetWindowThreadProcessId(hWnd, ctypes.byref(dwProcessId))
    if dwProcessId.value == 0:
        print("GetWindowThreadProcessId failed:", ctypes.windll.kernel32.GetLastError())
        return False

    # 获取托盘进程句柄
    hProcess = ctypes.windll.kernel32.OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, False, dwProcessId)
    if hProcess == 0:
        print("OpenProcess failed:", ctypes.windll.kernel32.GetLastError())
        return False

    # 在进程虚拟空间中分配内存,用来接收 TBBUTTON 结构体指针
    p_tbbutton = ctypes.windll.kernel32.VirtualAllocEx(hProcess, 0, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
    if p_tbbutton == 0:
        print("VirtualAllocEx failed:", ctypes.windll.kernel32.GetLastError())
        return False

    # 初始化
    dw_addr_dwData = 0
    buff = ctypes.create_string_buffer(1024)
    h_mainWnd = None
    i_data_offset = 12
    i_str_offset = 18

    # 判断 x64
    if Is64bitSystem():
        i_data_offset += 4
        i_str_offset += 6

    # 获取托盘图标个数
    i_buttons = ctypes.windll.user32.SendMessageW(hWnd, TB_BUTTONCOUNT, 0, 0)
    if i_buttons != 0:
        print("TB_BUTTONCOUNT message failed:", ctypes.windll.kernel32.GetLastError())
        return False
    i_buttons = 2

    # 遍历托盘
    for i in range(i_buttons):
        # 获取 TBBUTTON 结构体指针
        if not ctypes.windll.user32.SendMessageW(hWnd, TB_GETBUTTON, i, p_tbbutton):
            print("TB_GETBUTTON message failed:", ctypes.windll.kernel32.GetLastError())
            return False

        # 读 TBBUTTON.dwData(附加信息)
        ctypes.windll.kernel32.ReadProcessMemory(hProcess, ctypes.c_void_p(p_tbbutton.value + i_data_offset), ctypes.byref(dw_addr_dwData), 4, None)
        if dw_addr_dwData:
            ctypes.windll.kernel32.ReadProcessMemory(hProcess, ctypes.c_void_p(dw_addr_dwData), buff, 1024, None)
            h_mainWnd = ctypes.cast(buff.raw[:4], ctypes.POINTER(wintypes.HWND)).contents
            ws_filePath = ctypes.c_wchar_p(buff.raw[i_str_offset:i_str_offset + ctypes.sizeof(wintypes.WCHAR) * ctypes.sizeof(wintypes.MAX_PATH)])
            ws_tile = ctypes.c_wchar_p(buff.raw[i_str_offset + ctypes.sizeof(wintypes.WCHAR) * ctypes.sizeof(wintypes.MAX_PATH):])
            print("hMainWnd =", hex(h_mainWnd.value))
            print("strFilePath =", ws_filePath.value)
            print("strTile =", ws_tile.value)

        # 清理
        dw_addr_dwData = 0
        h_mainWnd = None

        print()

    ctypes.windll.kernel32.VirtualFreeEx(hProcess, p_tbbutton, 0, MEM_RELEASE)
    ctypes.windll.kernel32.CloseHandle(hProcess)

    return True

def main():
    # 解决控制台中文 '?'
    import locale
    locale.setlocale(locale.LC_ALL, "chs")

    # 获取托盘句柄
    h_tray = FindTrayWnd()
    h_tray_fold = FindNotifyIconOverflowWindow()

    # 遍历托盘窗口
    if not EnumNotifyWindow(h_tray) or not EnumNotifyWindow(h_tray_fold):
        print("EnumNotifyWindow false.")

    input()

if __name__ == "__main__":
    main()

但是,它不适用于Windows 11... 在代码第92行,我发现“i_buttons”变量始终为0。 我不想使用任何大型库(例如 PyQt)来完成我的问题,谢谢。

python windows ctypes system-tray
1个回答
0
投票

您上传的上述代码旨在使用 python 和 Windows API 通过 ctypes 模块获取窗口上的系统托盘图标。然而,它包含一些需要澄清的问题和复杂性。

这是一个代码;

import ctypes
from ctypes import wintypes

TB_BUTTONCOUNT = 0 * 0400 + 24
TB_GETBUTTON = 0 * 0417

class TBBUTTON(ctypes.Structure):
  _fields_ = [
               ('iBitmap',ctypes.c_int),
               ('idcommand',ctypes.c_int),
                ('fsState', ctypes.c_byte),
        ('fsStyle', ctypes.c_byte),
        ('bReserved', ctypes.c_byte * 6),
        ('dwData', ctypes.c_void_p),
        ('iString', ctypes.c_void_p)
    ]

def find_tray_toolbar():
    # Locate system tray toolbar
    hwnd_tray = ctypes.windll.user32.FindWindowW("Shell_TrayWnd", None)
    hwnd_notify = ctypes.windll.user32.FindWindowExW(hwnd_tray, None, "TrayNotifyWnd", None)
    hwnd_toolbar = ctypes.windll.user32.FindWindowExW(hwnd_notify, None, "ToolbarWindow32", None)
    return hwnd_toolbar

def get_tray_icon_count(hwnd_toolbar):
    return ctypes.windll.user32.SendMessageW(hwnd_toolbar, TB_BUTTONCOUNT, 0, 0)

def main():
    hwnd_toolbar = find_tray_toolbar()
    if not hwnd_toolbar:
        print("System tray toolbar not found.")
        return
    
    button_count = get_tray_icon_count(hwnd_toolbar)
    print(f"Number of tray icons: {button_count}")

if __name__ == "__main__":
    main()
           
© www.soinside.com 2019 - 2024. All rights reserved.