Volo di notte

お勉強の成果メモや日常のこと

[Python] タスクトレイ アイコンのツールチップ テキストを取得する

タスクトレイ(通知領域)に収められているアイコンのツールチップには、タスク自動化などで使える情報がたくさんあります。 例えばGoogleフォトバックアップでは「写真100枚をバックアップしました」などとお知らせしてくれます。

これをPythonで取得して使えるようなlist形式にします。

ツールチップのイメージ

f:id:Chachay:20161004215724p:plain

2つの通知領域

Windows 7以降には、常時表示される通知アイコンと通常隠れていて表示をOn/Offできるものがあります。

(それぞれの切り替えには下記を参照してください)

Windows 10 タスクバーの通知領域のアイコンを非表示にする

それぞれのアイコンのツールチップは別々のWindowにぶら下がっており、Spy++などでハンドルを見ると

常時表示される通知領域
Shell_TrayWnd > TrayNotifyWnd > SysPager > ToolbarWindow32 以下の"ボタン"としての性格
通常非表示の通知領域
NotifyIconOverflowWindow > ToolbarWindow32 以下の"ボタン"としての性格

を持つことがわかります。

ツールチップテキストの取得

WindowsAPIをふんだんに使うので、まずPython for Windows Extensionsが必要になります。Anacondaの人は、最初から入っていると思います。

ツールバーのWindowハンドルをFindWindow/FindWindowExで取得したら、 あとはメモリからテキストを読み込んでいくだけの簡単なお仕事になります。

# -*- coding: utf-8 -*-
import win32gui, win32process, win32api, win32con
import ctypes, copy

PAGE_READWRITE = 0x04
MEM_COMMIT     = 0x1000
MEM_RESERVE    = 0x2000
MEM_RELEASE    = 0x8000
TB_BUTTONCOUNT = 0x418
TB_GETBUTTONTEXT = 0x42D

tipslist = []

def GetTips(hWnd):
    threadId, processId = win32process.GetWindowThreadProcessId(hWnd)

    pHandle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, 0, processId)
    VirtualM = ctypes.windll.kernel32.VirtualAllocEx(pHandle.handle, 0, 256, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)

    # タスクアイコン数取得
    count = win32api.SendMessage(hWnd, TB_BUTTONCOUNT, 0, 0)

    for i in range(count):
        res = win32api.SendMessage(hWnd, TB_GETBUTTONTEXT, i, VirtualM)
        STR = ctypes.create_string_buffer(1024)
        print i,res, STR
        ctypes.windll.kernel32.ReadProcessMemory(pHandle.handle, VirtualM, STR, 1024, 0)
        tipslist.append(copy.copy(STR.value.decode('cp932')))
        print STR.value.decode('cp932')

    ctypes.windll.kernel32.VirtualFreeEx(pHandle.handle, VirtualM, 0, MEM_RELEASE)
    ctypes.windll.kernel32.CloseHandle(pHandle.handle)

# 常時表示のタスクトレイからWindow Handle取得
hW = win32gui.FindWindow("Shell_TrayWnd", None)
hW = win32gui.FindWindowEx(hW, 0, "TrayNotifyWnd", None)
hW = win32gui.FindWindowEx(hW, 0, "SysPager", None)
hW = win32gui.FindWindowEx(hW, 0, "ToolbarWindow32", None)
GetTips(hW)

# 通常非表示のタスクトレイからWindow Handle取得
hW = win32gui.FindWindow("NotifyIconOverflowWindow", None)
hW = win32gui.FindWindowEx(hW, 0, "ToolbarWindow32", None)
GetTips(hW)
    
# 取得した結果の表示
print("\nタスクアイコン数:", len(tipslist))
print(tipslist)