1 (изменено: k2, 2015-03-08 05:39:36)

Тема: AHK: Трей: определить процесс, иконка которого находится под мышью

Указываю мышью на иконку в трее. Есть ли возможность определить процесс (и другую информацию), отвечающий за иконку (не кликая по ней)?

Я смотрел тему "TrayIcon - Sean's TrayIcon for Unicode and 64 bit " , но мой вопрос там не решается.

2

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

AHK: Работа с треем

3

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

k2, ознакомьтесь с этой темой, отредактируйте свой пост.
ypppu, и как можно, воспользовавшись данной тобой ссылкой, решить задачу?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

4

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Это позволит получить список процессов, создавших иконки в трее. Возможно, этого уже достаточно, а остальное - изобретение велосипеда.

5

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

ypppu пишет:

остальное - изобретение велосипеда.

Да ну? Код в студию! Просим, просим!

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

6

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Вот код:

#NoTrayIcon
SetBatchLines, -1

PROCESS_VM_OPERATION := (0x8)
PROCESS_VM_READ := (0x10)
PROCESS_QUERY_INFORMATION := (0x400)
SizeOfTBBUTTON := 20, SizeOfTRAYDATA := 24
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
PAGE_READWRITE := 0x4
WM_USER := 0x400
TB_BUTTONCOUNT := (WM_USER + 24)
TB_GETBUTTON := (WM_USER + 23)
WM_WININICHANGE := 0x1A
TB_DELETEBUTTON := (WM_USER + 22)
WM_SETTINGCHANGE := WM_WININICHANGE

hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32  ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
   hChild := DllCall("FindWindowEx", UInt, A_Index = 1 ? hShell_TrayWnd : hChild
                                   , UInt, 0, Str, A_LoopField, UInt, 0)
; последнее вложенное — искомое окно — ToolbarWindow32 делаем последним найденным
WinWait, ahk_id %hChild%
WinGet, PID, PID
hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ, UInt, 0, UInt, PID)
lpData := DllCall("VirtualAllocEx", UInt, hProcess, UInt, 0
                                  , UInt, SizeOfTBBUTTON
                                  , UInt, MEM_COMMIT
                                  , UInt, PAGE_READWRITE)
DetectHiddenWindows, On
VarSetCapacity(TBBUTTON, SizeOfTBBUTTON)
VarSetCapacity(TRAYDATA, SizeOfTRAYDATA)
VarSetCapacity(FilePath, A_IsUnicode ? 600 : 300)
Index := 0
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
   SendMessage, TB_GETBUTTON, Index, lpData
   DllCall("ReadProcessMemory", UInt, hProcess, UInt, lpData
                              , UInt, &TBBUTTON
                              , UInt, SizeOfTBBUTTON, UInt, 0)

   DllCall("ReadProcessMemory", UInt, hProcess, UInt, NumGet(TBBUTTON, 12)
                              , UInt, &TRAYDATA
                              , UInt, SizeOfTRAYDATA, UInt, 0)

   WinGet, PID, PID, % "ahk_id " NumGet(TRAYDATA)
   if !PID
      SendMessage, TB_DELETEBUTTON, Index--  ; в случае удаления индексы уменьшаются на 1
   Else
   {
      hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION, UInt, 0, UInt, PID)
      if !DllCall("GetProcessImageFileName" . (A_IsUnicode ? "W" : "A")
                                                , UInt, hProc
                                                , Str, FilePath, UInt, 300)
         DllCall("Psapi\GetProcessImageFileName" . (A_IsUnicode ? "W" : "A")
                                                   , UInt, hProc
                                                   , Str, FilePath, UInt, 300)
      FilePaths .= FilePath . "`n"
      DllCall("CloseHandle", UInt, hProc)
   }
   Index++
}

if (Index < IconCount)
   SendMessage, WM_SETTINGCHANGE,,,, ahk_class Shell_TrayWnd

DllCall("VirtualFreeEx", UInt, hProcess , UInt, lpData, UInt, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", UInt, hProcess)

MsgBox, % SubStr(FilePaths, 1, -1)

7

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

ypppu пишет:

Вот код:

У меня этот код удалил все иконки из трея и выдал пустое сообщение. Как теперь вернуть их обратно и определить процесс иконки под курсором?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

8

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Windows XP SP3, AutoHotkey 1.1.19.1 Unicode 32-bit полёт нормальный, список получен.

9

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

А куда летим? Какой список? И как это отвечает на поставленные вопросы? Как вернуть удалённые иконки в трей? Как определить иконку под курсором? У меня Win 7 64 AHK 64, если что. Но работать должно под любую версию.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

10

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Сначала пишем, потом думаем?

11

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Не понял, это ты о ком?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

А-у, мастер Йода, верни мои иконки!

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

13 (изменено: Irbis, 2015-03-07 18:54:13)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

+ OFF

Так проблема была найти процесс, сопоставленный иконке. Перефразируя, можно сказать: "Нэт иконки - нэт проблемы".

14

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Irbis пишет:

Так проблема была найти процесс, сопоставленный иконке.

Иконке под курсором.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

15 (изменено: k2, 2015-03-08 04:26:17)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Вмешаюсь.  Не очень понял, что нужно изменить в заголовке темы, удалил случайно оставшийся "?" в конце.

Да, список процессов получить можно, см. тут обновлённый код (Unicode+все разрядности Windows).

Но мне хотелось бы найти соответствие между конкретной иконкой, на которую указывает указатель мыши, - и процессом, эту иконку оставившим.

16

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

k2, в заголовке ничего менять не нужно. Ознакомьтесь с указанной темой, обратите внимание на оформление ссылок, отредактируйте свои посты.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

17

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Не понимаю, чего здесь сложного?

f11::
ControlGetText, TextToolTipUnderMouse,, ahk_class tooltips_class32

test := TrayIcon_GetInfo()
Loop, % test.MaxIndex()
{
   str := test[A_Index].tooltip
   if (str = TextToolTipUnderMouse)
   {
      str := test[A_Index].place " - " test[A_Index].idx " - " test[A_Index].process " - " test[A_Index].hwnd " - " test[A_Index].idcmd
      break
   }
}
MsgBox % str 


TrayIcon_GetInfo(sExeName:="") {
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On   

    oTrayInfo := Object()
    For key, sTrayP in ["Shell_TrayWnd", "NotifyIconOverflowWindow"]
    {   
        idxTB := TrayIcon_GetTrayBar()
        WinGet, pidTaskbar, PID, ahk_class %sTrayP%

        hProc := DllCall( "OpenProcess",    UInt,0x38, Int,0, UInt,pidTaskbar                       )
        pRB   := DllCall( "VirtualAllocEx", Ptr,hProc, Ptr,0, UInt,20,        UInt,0x1000, UInt,0x4 )

        szBtn := VarSetCapacity( btn, (A_Is64bitOS) ? 32 : 24, 0 )
        szNfo := VarSetCapacity( nfo, (A_Is64bitOS) ? 32 : 24, 0 )
        szTip := VarSetCapacity( tip, 128 * 2,                 0 )

        SendMessage, 0x418, 0, 0, ToolbarWindow32%idxTB%, ahk_class %sTrayP% ; TB_BUTTONCOUNT
        Loop, %ErrorLevel%
        {
            SendMessage, 0x417, A_Index - 1, pRB, ToolbarWindow32%idxTB%, ahk_class %sTrayP% ; TB_GETBUTTON

            DllCall( "ReadProcessMemory", Ptr,hProc, Ptr,pRB, Ptr,&btn, UInt,szBtn, UInt,0 )

            iBitmap := NumGet( btn, 0                       )
            idCmd   := NumGet( btn, 4                       )
            Statyle := NumGet( btn, 8                       )
            dwData  := NumGet( btn, (A_Is64bitOS) ? 16 : 12 )
            iString := NumGet( btn, (A_Is64bitOS) ? 24 : 16 )

            DllCall( "ReadProcessMemory", Ptr,hProc, Ptr,dwData, Ptr,&nfo, UInt,szNfo, UInt,0 )

            hWnd  := NumGet( nfo, 0                       )
            uID   := NumGet( nfo, (A_Is64bitOS) ? 8  : 4  )
            nMsg  := NumGet( nfo, (A_Is64bitOS) ? 12 : 8  )
            hIcon := NumGet( nfo, (A_Is64bitOS) ? 24 : 20 )

            WinGet,      pid,      PID,         ahk_id %hWnd%
            WinGet,      sProcess, ProcessName, ahk_id %hWnd%
            WinGetClass, sClass,                ahk_id %hWnd%

            If ( !sExeName || (sExeName == sProcess) || (sExeName == pid) )
                DllCall( "ReadProcessMemory", Ptr,hProc, Ptr,iString, Ptr,&tip, UInt,szTip, UInt,0 )
              , oTrayInfo.Insert({ "idx": A_Index-1, "idcmd": idCmd, "pid": pid, "uid": uID, "msgid": nMsg
                                 , "hicon": hIcon, "hwnd": hWnd, "class": sClass, "process": sProcess
                                 , "tooltip": StrGet(&tip, "UTF-16"), "place": sTrayP })
        }
        
        DllCall( "VirtualFreeEx", Ptr,hProc, Ptr,pRB, UInt,0, UInt,0x8000 )
        DllCall( "CloseHandle",   Ptr,hProc                               )
    }
    DetectHiddenWindows, %d%
    Return oTrayInfo
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Hide
; Description ..: Hide or unhide a tray icon.
; Parameters ...: idCmd  - Command identifier associated with the button.
; ..............: sTrayP - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
; ..............: bHide  - True for hide, False for unhide.
; Info .........: TB_HIDEBUTTON message - http://goo.gl/oelsAa
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Hide(idCmd, sTrayP:="Shell_TrayWnd", bHide:=True) {
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x404, idCmd, bHide, ToolbarWindow32%idxTB%, ahk_class %sTrayP% ; TB_HIDEBUTTON
    SendMessage, 0x1A, 0, 0, , ahk_class %sTrayP%
    DetectHiddenWindows, %d%
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Remove
; Description ..: Remove a Tray icon. It should be more reliable than TrayIcon_Delete.
; Parameters ...: hWnd - Window handle.
; ..............: uID  - Application defined identifier for the icon.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Remove(hWnd, uID) {
    sz := VarSetCapacity( NID, (A_PtrSize == 4) ? 832 : 848, 0 )
    NumPut( sz, NID, 0 ), NumPut( hWnd, NID, A_PtrSize ), NumPut( uID, NID, A_PtrSize*2 )
    DllCall( "Shell32.dll\Shell_NotifyIcon", UInt,2, Ptr,&NID )
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Delete
; Description ..: Delete a tray icon.
; Parameters ...: idx - 0 based tray icon index.
; ..............: sTrayP - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
; Info .........: TB_DELETEBUTTON message - http://goo.gl/L0pY4R
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Delete(idx, sTrayP:="Shell_TrayWnd") {
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x416, idx, 0, ToolbarWindow32%idxTB%, ahk_class %sTrayP% ; TB_DELETEBUTTON
    SendMessage, 0x1A, 0, 0, , ahk_class %sTrayP%
    DetectHiddenWindows, %d%
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Move
; Description ..: Move a tray icon.
; Parameters ...: idxOld - 0 based index of the tray icon to move.
; ..............: idxNew - 0 based index where to move the tray icon.
; ..............: sTrayP - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
; Info .........: TB_MOVEBUTTON message - http://goo.gl/1F6wPw
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Move(idxOld, idxNew, sTrayP:="Shell_TrayWnd") {
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x452, idxOld, idxNew, ToolbarWindow32%idxTB%, ahk_class %sTrayP% ; TB_MOVEBUTTON
    DetectHiddenWindows, %d%
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetTrayBar
; Description ..: Get the tray icon handle.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetTrayBar() {
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    WinGet, ControlList, ControlList, ahk_class Shell_TrayWnd
    RegExMatch(ControlList, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", nTB)

    Loop, %nTB%
    {
        ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class Shell_TrayWnd
        hParent := DllCall( "GetParent", Ptr,hWnd )
        WinGetClass, sClass, ahk_id %hParent%
        If (sClass <> "SysPager")
            Continue
        idxTB := A_Index
            Break
    }
    
    DetectHiddenWindows, %d%
    Return  idxTB
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetHotItem
; Description ..: Get the index of tray's hot item.
; Info .........: TB_GETHOTITEM message - http://goo.gl/g70qO2
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetHotItem() {
   idxTB := TrayIcon_GetTrayBar()
   SendMessage, 0x447, 0, 0, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd ; TB_GETHOTITEM
   Return ErrorLevel << 32 >> 32
}

18 (изменено: k2, 2015-03-08 09:32:37)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Malcev, большое спасибо, это  очень, очень остроумно.

К сожалению, поскольку это может работать только во время вывода подсказки, возникает ненадёжность. Подсказка иногда вообще упорно не появляется, во всяком случае у меня в Win XP.  А ещё у меня есть значок, вообще не имеющий подсказки, она - пустая (хотя, поскольку он единственный, - процесс, и всё остальное - определяется верно).

19

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Напишу попозже.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

20

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

К сожалению, поскольку это может работать только во время вывода подсказки, возникает ненадёжность.

Вот так надежней:
http://forum.script-coding.com/viewtopi … 700#p81700

21

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Так не надо.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

22

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Понятное дело, но пока других вариантов нету...

23

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Пишут, что есть возможность узнать, которые иконки скрытые. Если исключить их процессы, то список от teadrinker будет соответствовать ряду иконок, если считать справа налево (снизу вверх, если несколько рядов).

Ещё встречалась программа, которая определяет процессы, чьи иконки скрыты.

Ещё попадался скрипт на AutoIt. Вроде там готовое решение поставленного вопроса.

24

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Malcev пишет:

Понятное дело, но пока других вариантов нету...

Есть, но у компьютера только завтра вечером буду, пока праздную.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

25 (изменено: k2, 2015-03-09 00:51:40)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

- Вот так надежней:
- Так не надо.
Вроде читает и до появления подсказок, и погасшие подсказки. teadrinker, Malcev, почему "так не надо"?

26

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Потому что это ерунда. Текст подсказок не имеет отношения к теме, по нему нельзя однозначно определить процесс.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

27 (изменено: k2, 2015-03-09 04:49:50)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Не ерунда. С этим вместо ControlGetText скрипт стал рабочим. Поэтому мне интересно, чем это плохо.
Идеальное же решение - пообещал teadrinker .

28

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Ну так, а где ваш код определяющий с помощью Acc, идентификатор процесса?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

29

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

k2 пишет:

teadrinker, Malcev, почему "так не надо"?

Потому, что текст подсказки не обязан соответствовать названию процесса, его устанавливает разработчик, какой хочет. Кроме того, может быть много процессов с одинаковым названием.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

30

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Тогда другой вариант:

f11::
Acc := Acc_ObjectFromPoint(ChildId)
test := TrayIcon_GetInfo()
Loop, % test.MaxIndex()
{
   str := test[A_Index].idx + 1
   if (str = ChildId)
   {
      str := test[A_Index].place " - " test[A_Index].idx " - " test[A_Index].process " - " test[A_Index].hwnd " - " test[A_Index].idcmd
      break
   }
}
MsgBox % str 

31 (изменено: serzh82saratov, 2015-03-09 13:51:53)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Ну наконец то.
Ещё в примере не мешало бы добавить:

; ..............:             oTrayInfo[A_Index].pid     - Process ID.

И в "NotifyIconOverflowWindow" не работает.

Перед этим:

Acc := Acc_ObjectFromPoint(ChildId)

Надо ещё определить, что мышь именно над треем.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

32

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Сейчас пока без компьютера, но

Acc := Acc_ObjectFromPoint(ChildId)

здесь явно лишнее. Информацию о расположении иконки можно получить обычным способом с помощью сообщений.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

33 (изменено: serzh82saratov, 2015-03-10 08:56:08)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Увы не знаю с помощью каких сообщений, скорее всего получение координат всех иконок, и их сравнение с мышью. Но из того что имеем, можно например так слепить:


#SingleInstance Force   

1:: 
    MouseGetPos, , , WinID, ClassNN 
    If ClassNN != ToolbarWindow321
        Return
    WinGetClass, Class, ahk_id %WinID%
    If Class not in NotifyIconOverflowWindow,Shell_TrayWnd
        Return   
    If ObjectFromPoint(ChildId).accRole(childId) != 43  
        Return
    oTray := TrayIcon_GetInfo(Class)   
    MsgBox % "process: " oTray[ChildId].process "`n" 
                    . "pid: " oTray[ChildId].pid "`n"
                    . "hwnd: " oTray[ChildId].hwnd "`n"
                    . "ProcessPath: " oTray[ChildId].ProcessPath "`n"
                    . "CommandLine: " oTray[ChildId].CommandLine 
    Return

TrayIcon_GetInfo(sTrayP) {
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On    
    oTrayInfo := Object() 
    idxTB := TrayIcon_GetTrayBar()
    WinGet, pidTaskbar, PID, ahk_class %sTrayP% 
    hProc := DllCall("OpenProcess", UInt,0x38, Int,0, UInt,pidTaskbar)
    pRB := DllCall("VirtualAllocEx", Ptr,hProc, Ptr,0, UInt,20, UInt,0x1000, UInt,0x4) 
    szBtn := VarSetCapacity(btn, (A_Is64bitOS) ? 32 : 24, 0)
    szNfo := VarSetCapacity(nfo, (A_Is64bitOS) ? 32 : 24, 0)
    szTip := VarSetCapacity(tip, 128 * 2, 0) 
    SendMessage, 0x418, 0, 0, ToolbarWindow32%idxTB%, ahk_class %sTrayP% ; TB_BUTTONCOUNT
    Loop, %ErrorLevel%
    { 
        SendMessage, 0x417, A_Index - 1, pRB, ToolbarWindow32%idxTB%, ahk_class %sTrayP% ; TB_GETBUTTON 
        DllCall( "ReadProcessMemory", Ptr,hProc, Ptr,pRB, Ptr,&btn, UInt,szBtn, UInt,0) 
        dwData := NumGet(btn, (A_Is64bitOS) ? 16 : 12 )
        iString := NumGet(btn, (A_Is64bitOS) ? 24 : 16 ) 
        DllCall("ReadProcessMemory", Ptr,hProc, Ptr,dwData, Ptr,&nfo, UInt,szNfo, UInt,0) 
        hWnd := NumGet( nfo, 0)    
        WinGet, pid, PID, ahk_id %hWnd%
        WinGet, Process, ProcessName, ahk_id %hWnd%  
        WinGet, ProcessPath, ProcessPath, ahk_id %hWnd%  
        DllCall("ReadProcessMemory", Ptr,hProc, Ptr,iString, Ptr,&tip, UInt,szTip, UInt,0 )
        oTrayInfo.Insert({idx: A_Index-1, pid: pid, hwnd: hWnd, process: Process, ProcessPath: ProcessPath
            , CommandLine: ComObjGet("winmgmts:").Get("Win32_Process.Handle=" . pid).CommandLine})
    }
    DllCall("VirtualFreeEx", Ptr,hProc, Ptr,pRB, UInt,0, UInt,0x8000)
    DllCall("CloseHandle", Ptr,hProc) 
    DetectHiddenWindows, %d%
    Return oTrayInfo
}

TrayIcon_GetTrayBar() {
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    WinGet, ControlList, ControlList, ahk_class Shell_TrayWnd
    RegExMatch(ControlList, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", nTB) 
    Loop, %nTB%
    {
        ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class Shell_TrayWnd
        hParent := DllCall("GetParent", Ptr,hWnd)
        WinGetClass, sClass, ahk_id %hParent%
        If (sClass <> "SysPager")
            Continue
        idxTB := A_Index
            Break
    } 
    DetectHiddenWindows, %d%
    Return idxTB
}

ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "")  {
    Static h
    If Not h
        h := DllCall("LoadLibrary","Str","oleacc","Ptr")
    If DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
    Return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}

Библиотеки не требуются.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

34

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

так как код ниже срабатывает в трее не только над иконками.

Можно добавить, чтоб только под иконками:

state := Acc_GetStateText(Acc.accState(childId))
role := Acc_GetRoleText(Acc.accRole(childId))
if (state != "hot tracked") or (role != "push button")
   return

35

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Не совсем. Например над панелью задач может сработать. Ну и в принципе не верно использовать текст из accState и accRole, их значения будут зависеть от языка винды.

    Acc := ObjectFromPoint(ChildId)
    If (Acc.accRole(childId) != 43 || Acc.accState(childId) != 128)
        Return

Вопрос с панелью задач думаю можно решить проверкой контрола на ToolbarWindow321. В этом случае accState можно упразднить, я поправил код в 33.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

36 (изменено: Malcev, 2015-03-09 22:21:50)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Например над панелью задач может сработать

Это как? Не понял.

If (Acc.accRole(childId) != 43 || Acc.accState(childId) != 128)

А откуда взять эти цифры?

37

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

А откуда ты взял "push button" и "hot tracked"?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

38 (изменено: Malcev, 2015-03-09 22:23:17)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

А, точно. А то я сразу их в AhkSpy и не приметил.

Например над панелью задач может сработать

Это как? Не понял.

39 (изменено: serzh82saratov, 2015-03-09 22:27:51)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

У закреплённой кнопки в панели задач, но если её приложение не запущено, тоже самое:

If (Acc.accRole(childId) != 43 || Acc.accState(childId) != 128)
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

40

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Но так как ты сейчас отлавливаешь нажатие по контролу, то сейчас ошибок больше быть не должно?

41

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Не понял вопроса.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

42

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Я имею в виду эту часть кода:

If ClassNN != ToolbarWindow321
    Return

В  ToolbarWindow321 кнопку закрепить невозможно и следовательно скрипт не будет ошибочно срабатывать.

43 (изменено: serzh82saratov, 2015-03-09 23:41:44)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

В  ToolbarWindow321 кнопку закрепить невозможно

Снова не понимаю твоё выражение. ToolbarWindow321 это уже не панель задач.
Просто иконки трея могут быть только в таковом контроле.
В AhkSpy проведи по всему Shell_TrayWnd следя за красной рамкой. Собственно:

    If ObjectFromPoint(ChildId).accRole(childId) != 43  
        Return

Нужно теперь только для проверки пустых зон в NotifyIconOverflowWindow.
Можно упростить до:

    ObjectFromPoint(ChildId)
    If !ChildId
        Return
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

44

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Я про это и имел в виду, что прикрепленные кнопки с панели задач не могут быть перенесены в ToolbarWindow321.

45

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Информация по Ctrl + RButton над иконкой трея:

^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
      
   if !hToolbar := ControlMousePos(XM, YM)
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Курсор не над треем", Str, "", UInt, 0)
   
   WinExist("ahk_id" hToolbar)
   WinGet, PID, PID
   
   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  {
      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
      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
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

46

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Большое спасибо за новые варианты. Мне для моей задачи хватило определения имени процесса (по подсказкам), но последние варианты, конечно, отвечают именно на поставленный вопрос.

47

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

k2 пишет:

Мне для моей задачи хватило определения имени процесса

Если не секрет, что Вы будете делать с этим скриптом?

48 (изменено: Malcev, 2015-03-10 18:36:06)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Информация по Ctrl + RButton над иконкой трея:

Call to nonexist function:    
Format("0x{:X}", hWnd)
            , CommandLine: ComObjGet("winmgmts:").Get("Win32_Process.Handle=" . PID).CommandLine, Tooltip: Tooltip}

49

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Обновись.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

50 (изменено: k2, 2015-03-10 21:39:06)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

- Если не секрет
- Секрета нет, но не уверен, одобрят ли тут мои странности.
Меня всегда раздражало, что реакция иконок не стандартизирована: одни отзываются на одинарный щелчок, другие - на двойной. Тем более, сложно объяснить это странное поведение другому человеку. Решил делать двойной клик по иконкам, его требующим - скриптом. Для этого достаточно определять соответствие "иконка-имя процесса". Теперь у меня все иконки - однокликовые.

51

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

teadrinker
Заметил в коде в Коллекции:


"VirtualAllocEx", UInt, this.hProc, UInt, 0, UInt, size

Первый параметр хэндл, т.е. Ptr. Третий — тип SIZE_T, тоже Ptr.


"ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, size, UInt, 0

Два последних параметра — тип SIZE_T, т.е. Ptr.

52

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Спасибо, отредактировано.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

53 (изменено: teadrinker, 2015-04-07 04:01:10)

Re: AHK: Трей: определить процесс, иконка которого находится под мышью

Более интересный пример. Создаём своё меню для иконок трея и NotifyIconOverflowWindow. Меню показывается по Ctrl + RButton над иконкой.

#NoEnv
SetBatchLines, -1
Return

Esc:: ExitApp

#If oResult := IsMouseOverTray()
^RButton Up::ShowMyMenu(oResult), oResult := ""

ShowMyMenu(oMousePosInfo)
{
   oIconInfo := GetTrayIconInfoFromPos(oMousePosInfo)
   
   Icon  := Func("GetIcon").Bind(oIconInfo)
   Show  := Func("ShowInfo").Bind(oIconInfo)
   Open  := Func("OpenFolder").Bind(oIconInfo)
   Close := Func("CloseProcess").Bind(oIconInfo)
   
   Menu, MyMenu, UseErrorLevel
   Menu, MyMenu, DeleteAll
   Menu, MyMenu, Add, Завершить процесс, % Close
   Menu, MyMenu, Add, Показать иконку в своём окне, % Icon
   Menu, MyMenu, Add, Показать информацию, % Show
   Menu, MyMenu, Add, Открыть папку, % Open
   Menu, MyMenu, Show
}
   
GetTrayIconInfoFromPos(oMousePosInfo)
{
   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
   
   WinExist("ahk_id" oMousePosInfo.hToolbar)
   WinGet, PID, PID
   
   if !IsObject(RemoteBuff := New RemoteBuffer(PID, SizeOfTBBUTTON))
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось создать удалённый буфер`nОшибка " A_LastError, Str, "", UInt, 0)
   
   WinGetPos, xTB, yTB
   POINT := (oMousePosInfo.X - xTB) | (oMousePosInfo.Y - yTB) << 32
   
   SendMessage, TB_BUTTONCOUNT
   Loop % ErrorLevel  {
      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)
      TraydataOffset := NumGet(&TBBUTTON + 8 + PtrSize) - RemoteBuff.ptr
      TooltipOffset := NumGet(&TBBUTTON + 8 + PtrSize*2) - RemoteBuff.ptr
      RemoteBuff.Read(TRAYDATA, SizeOfTRAYDATA, TraydataOffset)
      RemoteBuff.Read(String, SizeOfiString, TooltipOffset)
      
      Tooltip := StrGet(&String, "UTF-16")
      hWnd    := NumGet(TRAYDATA, PtrSize = 4 ? "UInt" : "UInt64")
      uID     := NumGet(TRAYDATA, PtrSize, "UInt")
      nMsg    := NumGet(TRAYDATA, PtrSize + 4, "UInt")
      hIcon   := NumGet(TRAYDATA, PtrSize + 16, PtrSize = 4 ? "UInt" : "UInt64")
      
      DHW_Prev := A_DetectHiddenWindows
      DetectHiddenWindows, On
      WinExist("ahk_id" hWnd)
      WinGet, Name, ProcessName
      WinGet, ProcessPath, ProcessPath
      WinGet, PID, PID
      DetectHiddenWindows, %DHW_Prev%
      
      Return { ProcessName: Name, PID: PID, ProcessPath: ProcessPath, hWnd: Format("{:#x}", hWnd), idx: A_Index - 1
             , CommandLine: ComObjGet("winmgmts:").Get("Win32_Process.Handle=" . PID).CommandLine, hTB: oMousePosInfo.hToolbar
             , Tooltip: Tooltip, ID: Format("{:#x}", uID), Msg: Format("{:#x}", nMsg), hIcon: Format("{:#x}", hIcon) }
   }
}

IsMouseOverTray()
{
   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: hToolbar, X: X, Y: Y}
}

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
   }
}

CloseProcess(oInfo)
{
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinExist("ahk_id" oInfo.hWnd)
   WinClose
   WinWaitClose,,, 2
   close := !ErrorLevel
   DetectHiddenWindows, % DHW_Prev
   if close
      Return
   
   MsgBox, 4,, % "Не удалось корректно завершить процесс " oInfo.ProcessName ". Убить его?"
   IfMsgBox, No
      Return
   
   Process, Close, % oInfo.PID
   Process, WaitClose, % oInfo.PID, 2
   if ErrorLevel  {
      MsgBox, % "Не удалось завершить процесс " oInfo.ProcessName
      Return
   }
   SendMessage, TB_DELETEBUTTON := 0x416, oInfo.idx,,, % "ahk_id" oInfo.hTB
   SendMessage, WM_SETTINGCHANGE := 0x1A,,,, % "ahk_id" oInfo.hTB
}

ShowInfo(oInfo)
{
   for k, v in ["PID", "ProcessName", "ProcessPath", "CommandLine", "Msg", "ID", "hWnd", "hIcon", "ToolTip"]
      list .= v " = " oInfo[v] "`r`n"
   Run, notepad.exe,,, PID
   WinWait, ahk_pid %PID%
   SendMessage, WM_SETICON := 0x80, ICON_SMALL := 0, oInfo.hIcon   ; иконка в строку заголовка окна
   
   if script := RegExMatch(oInfo.CommandLine, "i)\.exe.*\.ahk")
      ScriptName := RegExReplace(oInfo.CommandLine, "i)(*UCP).*\W(\w+\.ahk).*", "$1")
   title := script ? ScriptName : oInfo.ProcessName
   SendMessage, WM_SETTEXT := 0xC,, &title
   ControlSetText, Edit1, % Trim(list, "`r`n")
}

OpenFolder(oInfo)
{
   if !RegExMatch(oInfo.CommandLine, "i)\.exe.*\.ahk")
      FilePath := oInfo.ProcessPath
   else  {
      if !FileExist(FilePath := RegExReplace(oInfo.CommandLine, "i).*([a-z]:\\.*\.ahk).*", "$1"))  {
         MsgBox, 4,, Папка скрипта не найдена. Открыть папку исполнимого файла?
         IfMsgBox, Yes
            FilePath := oInfo.ProcessPath
         else
            FilePath := ""
      }
   }
   if FilePath
      Run, % "Explorer /select`, """ . FilePath . """"
}

GetIcon(oInfo)
{
   static WM_SETICON := 0x80, ICON_SMALL := 0, SS_ICON := 0x3, STM_SETIMAGE := 0x172, IMAGE_ICON := 1
   
   Gui, MyGui:New, +LastFound -DPIScale
   Gui, Add, Pic, x80 y40 w32 h32 %SS_ICON%
   
   hIcon := oInfo.hIcon
   SendMessage, WM_SETICON, ICON_SMALL, hIcon   ; иконка в строку заголовка окна
   PostMessage, STM_SETIMAGE, IMAGE_ICON, hIcon, Static1  ; иконка в контрол Picture
   
   WinGetPos, X, Y,,, % "ahk_id" oInfo.hTB
   Gui, Show, % "w192 h112 x" X " y" Y - 160, Tray Icon
}

MyGuiClose()
{
   Gui, MyGui:Destroy
}

Можно также создавать разные меню для каждой иконки, ориентируясь на её ProcessName.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder