如何遍历系统托盘并获取其中的图标信息? 比如图标,创建它的过程...
我找到了一个满足我要求的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 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()