Facebook
From Cream Mosquito, 3 Years ago, written in Plain Text.
Embed
Download Paste or View Raw
Hits: 176
  1. ; ----------------------------------------------------------------------------------------------------------------------
  2. ; Name ..........: TrayIcon library
  3. ; Description ...: Provide some useful functions to deal with Tray icons.
  4. ; AHK Version ...: AHK_L 1.1.22.02 x32/64 Unicode
  5. ; Code from .....: Sean (http://www.autohotkey.com/forum/viewtopic.php?t=17314)
  6. ; Author ........: Cyruz (http://ciroprincipe.info) (http://ahkscript.org/boards/viewtopic.php?f=6&t=1229)
  7. ; Mod from ......: Fanatic Guru - Cyruz
  8. ; License .......: WTFPL - http://www.wtfpl.net/txt/copying/
  9. ; Version Date ..: 2019.03.12
  10. ; Upd.20160120 ..: Fanatic Guru - Went through all the data types in the DLL and NumGet and matched them up to MSDN
  11. ; ...............:                which fixed idCmd.
  12. ; Upd.20160308 ..: Fanatic Guru - Fix for Windows 10 NotifyIconOverflowWindow.
  13. ; Upd.20180313 ..: Fanatic Guru - Fix problem with "VirtualFreeEx" pointed out by nnnik.
  14. ; Upd.20180313 ..: Fanatic Guru - Additional fix for previous Windows 10 NotifyIconOverflowWindow fix breaking non
  15. ; ...............:                hidden icons.
  16. ; Upd.20190312 ..: Cyruz        - Added TrayIcon_Set, code merged and refactored.
  17. ; ----------------------------------------------------------------------------------------------------------------------
  18.  
  19. ; ----------------------------------------------------------------------------------------------------------------------
  20. ; Function ......: TrayIcon_GetInfo
  21. ; Description ...: Get a series of useful information about tray icons.
  22. ; Parameters ....: sExeName  - The exe for which we are searching the tray icon data. Leave it empty to receive data for
  23. ; ...............:             all tray icons.
  24. ; Return ........: oTrayInfo - An array of objects containing tray icons data. Any entry is structured like this:
  25. ; ...............:             oTrayInfo[A_Index].idx     - 0 based tray icon index.
  26. ; ...............:             oTrayInfo[A_Index].idcmd   - Command identifier associated with the button.
  27. ; ...............:             oTrayInfo[A_Index].pid     - Process ID.
  28. ; ...............:             oTrayInfo[A_Index].uid     - Application defined identifier for the icon.
  29. ; ...............:             oTrayInfo[A_Index].msgid   - Application defined callback message.
  30. ; ...............:             oTrayInfo[A_Index].hicon   - Handle to the tray icon.
  31. ; ...............:             oTrayInfo[A_Index].hwnd    - Window handle.
  32. ; ...............:             oTrayInfo[A_Index].class   - Window class.
  33. ; ...............:             oTrayInfo[A_Index].process - Process executable.
  34. ; ...............:             oTrayInfo[A_Index].tray    - Tray Type (Shell_TrayWnd or NotifyIconOverflowWindow).
  35. ; ...............:             oTrayInfo[A_Index].tooltip - Tray icon tooltip.
  36. ; Info ..........: TB_BUTTONCOUNT message - http://goo.gl/DVxpsg
  37. ; ...............: TB_GETBUTTON message   - http://goo.gl/2oiOsl
  38. ; ...............: TBBUTTON structure     - http://goo.gl/EIE21Z
  39. ; ----------------------------------------------------------------------------------------------------------------------
  40.  
  41. TrayIcon_GetInfo(sExeName := "")
  42. {
  43.     d := A_DetectHiddenWindows
  44.     DetectHiddenWindows, On
  45.  
  46.     oTrayInfo := []
  47.     For key,sTray in ["Shell_TrayWnd", "NotifyIconOverflowWindow"]
  48.     {
  49.         idxTB := TrayIcon_GetTrayBar(sTray)
  50.         WinGet, pidTaskbar, PID, ahk_class %sTray%
  51.        
  52.         hProc := DllCall("OpenProcess",    UInt,0x38, Int,0, UInt,pidTaskbar)
  53.         pRB   := DllCall("VirtualAllocEx", Ptr,hProc, Ptr,0, UPtr,20, UInt,0x1000, UInt,0x04)
  54.  
  55.         szBtn := VarSetCapacity(btn, (A_Is64bitOS ? 32 : 20), 0)
  56.         szNfo := VarSetCapacity(nfo, (A_Is64bitOS ? 32 : 24), 0)
  57.         szTip := VarSetCapacity(tip, 128 * 2, 0)
  58.  
  59.         ; TB_BUTTONCOUNT = 0x0418
  60.         SendMessage, 0x0418, 0, 0, ToolbarWindow32%idxTB%, ahk_class %sTray%
  61.         Loop, %ErrorLevel%
  62.         {
  63.              ; TB_GETBUTTON 0x0417
  64.             SendMessage, 0x0417, A_Index-1, pRB, ToolbarWindow32%idxTB%, ahk_class %sTray%
  65.  
  66.             DllCall("ReadProcessMemory", Ptr,hProc, Ptr,pRB, Ptr,&btn, UPtr,szBtn, UPtr,0)
  67.  
  68.             iBitmap := NumGet(btn, 0, "Int")
  69.             idCmd   := NumGet(btn, 4, "Int")
  70.             fsState := NumGet(btn, 8, "UChar")
  71.             fsStyle := NumGet(btn, 9, "UChar")
  72.             dwData  := NumGet(btn, (A_Is64bitOS ? 16 : 12), "UPtr")
  73.             iString := NumGet(btn, (A_Is64bitOS ? 24 : 16), "Ptr")
  74.  
  75.             DllCall("ReadProcessMemory", Ptr,hProc, Ptr,dwData, Ptr,&nfo, UPtr,szNfo, UPtr,0)
  76.  
  77.             hWnd  := NumGet(nfo, 0, "Ptr")
  78.             uId   := NumGet(nfo, (A_Is64bitOS ?  8 :  4), "UInt")
  79.             msgId := NumGet(nfo, (A_Is64bitOS ? 12 :  8), "UPtr")
  80.             hIcon := NumGet(nfo, (A_Is64bitOS ? 24 : 20), "Ptr")
  81.  
  82.             WinGet, nPid, PID, ahk_id %hWnd%
  83.             WinGet, sProcess, ProcessName, ahk_id %hWnd%
  84.             WinGetClass, sClass, ahk_id %hWnd%
  85.  
  86.             If ( !sExeName || sExeName == sProcess || sExeName == nPid )
  87.             {
  88.                 DllCall("ReadProcessMemory", Ptr,hProc, Ptr,iString, Ptr,&tip, UPtr,szTip, UPtr,0)
  89.                 oTrayInfo.Push({ "idx"     : A_Index-1
  90.                                , "idcmd"   : idCmd
  91.                                , "pid"     : nPid
  92.                                , "uid"     : uId
  93.                                , "msgid"   : msgId
  94.                                , "hicon"   : hIcon
  95.                                , "hwnd"    : hWnd
  96.                                , "class"   : sClass
  97.                                , "process" : sProcess
  98.                                , "tooltip" : StrGet(&tip, "UTF-16")
  99.                                , "tray"    : sTray })
  100.             }
  101.         }
  102.         DllCall("VirtualFreeEx", Ptr,hProc, Ptr,pRB, UPtr,0, UInt,0x8000)
  103.         DllCall("CloseHandle",   Ptr,hProc)
  104.     }
  105.     DetectHiddenWindows, %d%
  106.     Return oTrayInfo
  107. }
  108.  
  109. ; ----------------------------------------------------------------------------------------------------------------------
  110. ; Function .....: TrayIcon_Hide
  111. ; Description ..: Hide or unhide a tray icon.
  112. ; Parameters ...: idCmd - Command identifier associated with the button.
  113. ; ..............: sTray - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
  114. ; ..............: bHide - True for hide, False for unhide.
  115. ; Info .........: TB_HIDEBUTTON message - http://goo.gl/oelsAa
  116. ; ----------------------------------------------------------------------------------------------------------------------
  117. TrayIcon_Hide(idCmd, sTray:="Shell_TrayWnd", bHide:=True)
  118. {
  119.     d := A_DetectHiddenWindows
  120.     DetectHiddenWindows, On
  121.     idxTB := TrayIcon_GetTrayBar()
  122.     SendMessage, 0x0404, idCmd, bHide, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_HIDEBUTTON
  123.     SendMessage, 0x001A, 0, 0, , ahk_class %sTray%
  124.     DetectHiddenWindows, %d%
  125. }
  126.  
  127. ; ----------------------------------------------------------------------------------------------------------------------
  128. ; Function .....: TrayIcon_Delete
  129. ; Description ..: Delete a tray icon.
  130. ; Parameters ...: idx   - 0 based tray icon index.
  131. ; ..............: sTray - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
  132. ; Info .........: TB_DELETEBUTTON message - http://goo.gl/L0pY4R
  133. ; ----------------------------------------------------------------------------------------------------------------------
  134. TrayIcon_Delete(idx, sTray:="Shell_TrayWnd")
  135. {
  136.     d := A_DetectHiddenWindows
  137.     DetectHiddenWindows, On
  138.     idxTB := TrayIcon_GetTrayBar()
  139.     SendMessage, 0x0416, idx, 0, ToolbarWindow32%idxTB%, ahk_class %sTrayPlace% ; TB_DELETEBUTTON = 0x0416
  140.     SendMessage, 0x001A, 0, 0, , ahk_class %sTrayPlace%
  141.     DetectHiddenWindows, %d%
  142. }
  143.  
  144. ; ----------------------------------------------------------------------------------------------------------------------
  145. ; Function .....: TrayIcon_Remove
  146. ; Description ..: Remove a Tray icon. It should be more reliable than TrayIcon_Delete.
  147. ; Parameters ...: hWnd - Window handle.
  148. ; ..............: uId  - Application defined identifier for the icon.
  149. ; Info .........: NOTIFYICONDATA structure  - https://goo.gl/1Xuw5r
  150. ; ..............: Shell_NotifyIcon function - https://goo.gl/tTSSBM
  151. ; ----------------------------------------------------------------------------------------------------------------------
  152. TrayIcon_Remove(hWnd, uId)
  153. {
  154.         VarSetCapacity(NID, szNID := ((A_IsUnicode ? 2 : 1) * 384 + A_PtrSize*5 + 40),0)
  155.         NumPut( szNID, NID, 0           )
  156.         NumPut( hWnd,  NID, A_PtrSize   )
  157.         NumPut( uId,   NID, A_PtrSize*2 )
  158.         Return DllCall("Shell32.dll\Shell_NotifyIcon", UInt,0x2, UInt,&NID)
  159. }
  160.  
  161. ; ----------------------------------------------------------------------------------------------------------------------
  162. ; Function .....: TrayIcon_Move
  163. ; Description ..: Move a tray icon.
  164. ; Parameters ...: idxOld - 0 based index of the tray icon to move.
  165. ; ..............: idxNew - 0 based index where to move the tray icon.
  166. ; ..............: sTray  - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
  167. ; Info .........: TB_MOVEBUTTON message - http://goo.gl/1F6wPw
  168. ; ----------------------------------------------------------------------------------------------------------------------
  169. TrayIcon_Move(idxOld, idxNew, sTray := "Shell_TrayWnd")
  170. {
  171.     d := A_DetectHiddenWindows
  172.     DetectHiddenWindows, On
  173.     idxTB := TrayIcon_GetTrayBar()
  174.     SendMessage, 0x452, idxOld, idxNew, ToolbarWindow32%idxTB%, ahk_class %sTrayPlace% ; TB_MOVEBUTTON = 0x452
  175.     DetectHiddenWindows, %d%
  176. }
  177.  
  178. ; ----------------------------------------------------------------------------------------------------------------------
  179. ; Function .....: TrayIcon_Set
  180. ; Description ..: Modify icon with the given index for the given window.
  181. ; Parameters ...: hWnd       - Window handle.
  182. ; ..............: uId        - Application defined identifier for the icon.
  183. ; ..............: hIcon      - Handle to the tray icon.
  184. ; ..............: hIconSmall - Handle to the small icon, for window menubar. Optional.
  185. ; ..............: hIconBig   - Handle to the big icon, for taskbar. Optional.
  186. ; Return .......: True on success, false on failure.
  187. ; Info .........: NOTIFYICONDATA structure  - https://goo.gl/1Xuw5r
  188. ; ..............: Shell_NotifyIcon function - https://goo.gl/tTSSBM
  189. ; ----------------------------------------------------------------------------------------------------------------------
  190. TrayIcon_Set(hWnd, uId, hIcon, hIconSmall:=0, hIconBig:=0)
  191. {
  192.     d := A_DetectHiddenWindows
  193.     DetectHiddenWindows, On
  194.     ; WM_SETICON = 0x0080
  195.     If ( hIconSmall )
  196.         SendMessage, 0x0080, 0, hIconSmall,, ahk_id %hWnd%
  197.     If ( hIconBig )
  198.         SendMessage, 0x0080, 1, hIconBig,, ahk_id %hWnd%
  199.     DetectHiddenWindows, %d%
  200.  
  201.     VarSetCapacity(NID, szNID := ((A_IsUnicode ? 2 : 1) * 384 + A_PtrSize*5 + 40),0)
  202.     NumPut( szNID, NID, 0                           )
  203.     NumPut( hWnd,  NID, (A_PtrSize == 4) ? 4   : 8  )
  204.     NumPut( uId,   NID, (A_PtrSize == 4) ? 8   : 16 )
  205.     NumPut( 2,     NID, (A_PtrSize == 4) ? 12  : 20 )
  206.     NumPut( hIcon, NID, (A_PtrSize == 4) ? 20  : 32 )
  207.    
  208.     ; NIM_MODIFY := 0x1
  209.     Return DllCall("Shell32.dll\Shell_NotifyIcon", UInt,0x1, Ptr,&NID)
  210. }
  211.  
  212. ; ----------------------------------------------------------------------------------------------------------------------
  213. ; Function .....: TrayIcon_GetTrayBar
  214. ; Description ..: Get the tray icon handle.
  215. ; Parameters ...: sTray - Traybar to retrieve.
  216. ; Return .......: Tray icon handle.
  217. ; ----------------------------------------------------------------------------------------------------------------------
  218. TrayIcon_GetTrayBar(sTray:="Shell_TrayWnd")
  219. {
  220.     d := A_DetectHiddenWindows
  221.     DetectHiddenWindows, On
  222.     WinGet, ControlList, ControlList, ahk_class %sTray%
  223.     RegExMatch(ControlList, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", nTB)
  224.     Loop, %nTB%
  225.     {
  226.         ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class %sTray%
  227.         hParent := DllCall( "GetParent", Ptr, hWnd )
  228.         WinGetClass, sClass, ahk_id %hParent%
  229.         If !(sClass == "SysPager" || sClass == "NotifyIconOverflowWindow" )
  230.             Continue
  231.         idxTB := A_Index
  232.         Break
  233.     }
  234.     DetectHiddenWindows, %d%
  235.     Return idxTB
  236. }
  237.  
  238. ; ----------------------------------------------------------------------------------------------------------------------
  239. ; Function .....: TrayIcon_GetHotItem
  240. ; Description ..: Get the index of tray's hot item.
  241. ; Return .......: Index of tray's hot item.
  242. ; Info .........: TB_GETHOTITEM message - http://goo.gl/g70qO2
  243. ; ----------------------------------------------------------------------------------------------------------------------
  244. TrayIcon_GetHotItem()
  245. {
  246.     idxTB := TrayIcon_GetTrayBar()
  247.     SendMessage, 0x0447, 0, 0, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd ; TB_GETHOTITEM = 0x0447
  248.     Return ErrorLevel << 32 >> 32
  249. }
  250.  
  251. ; ----------------------------------------------------------------------------------------------------------------------
  252. ; Function .....: TrayIcon_Button
  253. ; Description ..: Simulate mouse button click on a tray icon.
  254. ; Parameters ...: sExeName - Executable Process Name of tray icon.
  255. ; ..............: sButton  - Mouse button to simulate (L, M, R).
  256. ; ..............: bDouble  - True to double click, false to single click.
  257. ; ..............: nIdx     - Index of tray icon to click if more than one match.
  258. ; ----------------------------------------------------------------------------------------------------------------------
  259. TrayIcon_Button(sExeName, sButton:="L", bDouble:=False, nIdx:=1)
  260. {
  261.     d := A_DetectHiddenWindows
  262.     DetectHiddenWindows, On
  263.     WM_MOUSEMOVE      = 0x0200
  264.     WM_LBUTTONDOWN    = 0x0201
  265.     WM_LBUTTONUP      = 0x0202
  266.     WM_LBUTTONDBLCLK  = 0x0203
  267.     WM_RBUTTONDOWN    = 0x0204
  268.     WM_RBUTTONUP      = 0x0205
  269.     WM_RBUTTONDBLCLK  = 0x0206
  270.     WM_MBUTTONDOWN    = 0x0207
  271.     WM_MBUTTONUP      = 0x0208
  272.     WM_MBUTTONDBLCLK  = 0x0209
  273.     sButton := "WM_" sButton "BUTTON"
  274.     oIcons  := TrayIcon_GetInfo(sExeName)
  275.     If ( bDouble )
  276.         PostMessage, oIcons[nIdx].msgid, oIcons[nIdx].uid, %sButton%DBLCLK,, % "ahk_id " oIcons[nIdx].hwnd
  277.     Else
  278.     {
  279.         PostMessage, oIcons[nIdx].msgid, oIcons[nIdx].uid, %sButton%DOWN,, % "ahk_id " oIcons[nIdx].hwnd
  280.         PostMessage, oIcons[nIdx].msgid, oIcons[nIdx].uid, %sButton%UP,, % "ahk_id " oIcons[nIdx].hwnd
  281.     }
  282.     DetectHiddenWindows, %d%
  283.     Return
  284. }
  285.  
  286.  
  287.  
  288. ^b::
  289. TrayIcon_Button("AutoHotkey.exe", sButton:="r", bDouble:=False, nIdx:=1)
  290. return
  291.