Тема: AHK: Получение данных об иконке в трее под курсором
Скрипт выводит данные об иконке в трее или в окне NotifyIconOverflowWindow по клику правой кнопкой над ней при удержании Ctrl.
^RButton:: ; Ctrl + RButton
if !oTrayIconInfo := GetTrayIconInfoFromMousePos() {
MsgBox, Не удалось получить информацию!
Return
}
MsgBox, % "PID = " oTrayIconInfo.PID
. "`nProcessName = " oTrayIconInfo.ProcessName
. "`nProcessPath = " oTrayIconInfo.ProcessPath
. "`nCommandLine = " oTrayIconInfo.CommandLine
. "`nhWnd = " oTrayIconInfo.hWnd
. "`nTooltip = " oTrayIconInfo.Tooltip
Return
Esc:: ExitApp
GetTrayIconInfoFromMousePos()
{
/*
Недокументированная структура TRAYDATA
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
static WM_USER := 0x400, TB_BUTTONCOUNT := WM_USER + 24, TB_GETBUTTON := WM_USER + 23, TB_GETITEMRECT := WM_USER + 29
, PtrSize := A_Is64bitOS ? 8 : 4, SizeOfTBBUTTON := 8 + PtrSize*3, SizeOfTRAYDATA := 16 + PtrSize*2, SizeOfiString := 256
; проверяем, находится ли курсор над треем или над окном NotifyIconOverflowWindow
if !hToolbar := ControlMousePos(XM, YM)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Курсор не над треем", Str, "", UInt, 0)
WinExist("ahk_id" hToolbar)
WinGet, PID, PID
; создаём буфер в адресном пространстве процесса explorer.exe (которому принадлежит и окно трея)
if !IsObject(RemoteBuff := New RemoteBuffer(PID, SizeOfTBBUTTON))
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось создать удалённый буфер`nОшибка " A_LastError, Str, "", UInt, 0)
WinGetPos, xTB, yTB
POINT := (XM - xTB) | (YM - yTB) << 32
SendMessage, TB_BUTTONCOUNT
Loop % ErrorLevel {
; информация, возвращаемая сообщениями TB_GETITEMRECT и TB_GETBUTTON, находится в адресном пространстве
; процесса explorer.exe, поэтому для её чтения пользуемся созданным ранее буфером
; TB_GETITEMRECT возвращает в структуре RECT координаты иконки с индексом A_Index - 1 относительно окна трея или окна NotifyIconOverflowWindow
SendMessage, TB_GETITEMRECT, A_Index - 1, RemoteBuff.ptr
RemoteBuff.Read(RECT, 16)
; сравниваем координаты иконки с координатами мыши
if !DllCall("PtInRect", Ptr, &RECT, Int64, POINT)
continue
; если координаты мыши лежат внутри площади иконки, получаем и возвращаем информацию о ней
SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr
RemoteBuff.Read(TBBUTTON, SizeOfTBBUTTON)
DHW_Prev := A_DetectHiddenWindows
DetectHiddenWindows, On
; получаем смещение структуры TRAYDATA относительно нашего буфера
TraydataOffset := NumGet(&TBBUTTON + 8 + PtrSize) - RemoteBuff.ptr
; получаем смещение строки со всплывающей подсказкой иконки относительно нашего буфера
TooltipOffset := NumGet(&TBBUTTON + 8 + PtrSize*2) - RemoteBuff.ptr
RemoteBuff.Read(TRAYDATA, SizeOfTRAYDATA, TraydataOffset), WinExist("ahk_id" hWnd := NumGet(&TRAYDATA))
RemoteBuff.Read(String, SizeOfiString, TooltipOffset), Tooltip := StrGet(&String, "UTF-16")
WinGet, Name, ProcessName
WinGet, ProcessPath, ProcessPath
WinGet, PID, PID
DetectHiddenWindows, %DHW_Prev%
Return {ProcessName: Name, PID: PID, ProcessPath: ProcessPath, hWnd: Format("{:#x}", hWnd)
, CommandLine: ComObjGet("winmgmts:").Get("Win32_Process.Handle=" . PID).CommandLine, Tooltip: Tooltip}
}
}
ControlMousePos(ByRef X, ByRef Y)
{
CoordMode, Mouse
MouseGetPos, X, Y, hWnd, hControl, 2
WinGetClass, Class, ahk_id %hWnd%
if Class not in NotifyIconOverflowWindow,Shell_TrayWnd
Return
if (Class = "NotifyIconOverflowWindow")
ControlGet, hToolbar, hwnd,, ToolbarWindow321, ahk_id %hWnd%
else {
for k, v in ["TrayNotifyWnd", "SysPager", "ToolbarWindow32"]
hToolbar := DllCall("FindWindowEx", Ptr, k = 1 ? hWnd : hToolbar, Ptr, 0, Str, v, UInt, 0, Ptr)
if (hToolbar != hControl)
Return
}
Return hToolbar
}
Class RemoteBuffer
{
__New(PID, size)
{
static PROCESS_VM_OPERATION := 0x8, PROCESS_VM_WRITE := 0x20, PROCESS_VM_READ := 0x10
, MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x4
if !(this.hProc := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))
Return
if !(this.ptr := DllCall("VirtualAllocEx", Ptr, this.hProc, UInt, 0, Ptr, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
Return, "", DllCall("CloseHandle", Ptr, this.hProc)
}
__Delete()
{
DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
DllCall("CloseHandle", Ptr, this.hProc)
}
Read(ByRef LocalBuff, size, offset = 0)
{
VarSetCapacity(LocalBuff, size, 0)
if !DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, Ptr, size, Ptr, 0)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось прочитать данные`nОшибка " A_LastError, Str, "", UInt, 0)
Return 1
}
}
Вопросы можно задать в этой теме.