Anonymous
Как получить информацию о системном трее в Python?
Сообщение
Anonymous » 24 ноя 2024, 18:17
Как пройтись по панели задач и получить в нем информацию о значке?
Например, значок, процесс, который его создал...
Я нашел страницу, на которой соответствует моим требованиям, я переписал его код на 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) для решения своей проблемы, спасибо.
Подробнее здесь:
https://stackoverflow.com/questions/792 ... -in-python
1732461478
Anonymous
Как пройтись по панели задач и получить в нем информацию о значке? Например, значок, процесс, который его создал... Я нашел страницу, на которой соответствует моим требованиям, я переписал его код на Python, правильно используя ctypes. Исходный код основан на Windows 10. [code]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() [/code] Однако это не работает в Windows 11... В строке 92 кода я обнаружил, что переменная «i_buttons» всегда равна 0. />Я не хочу использовать ЛЮБУЮ большую библиотеку (например, PyQt) для решения своей проблемы, спасибо. Подробнее здесь: [url]https://stackoverflow.com/questions/79219443/how-to-get-system-tray-information-in-python[/url]