-
Notifications
You must be signed in to change notification settings - Fork 1
/
TrayIcon.ahk
240 lines (222 loc) · 12.2 KB
/
TrayIcon.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
; ----------------------------------------------------------------------------------------------------------------------
; Name ..........: TrayIcon library
; Description ...: Provide some useful functions to deal with Tray icons.
; AHK Version ...: AHK_L 1.1.22.02 x32/64 Unicode
; Original Author: Sean (http://goo.gl/dh0xIX) (http://www.autohotkey.com/forum/viewtopic.php?t=17314)
; Update Author .: Cyruz (http://ciroprincipe.info) (http://ahkscript.org/boards/viewtopic.php?f=6&t=1229)
; Mod Author ....: Fanatic Guru
; License .......: WTFPL - http://www.wtfpl.net/txt/copying/
; Version Date...: 2018 03 13
; Note ..........: Many people have updated Sean's original work including me but Cyruz's version seemed the most straight
; ...............: forward update for 64 bit so I adapted it with some of the features from my Fanatic Guru version.
; Update 20160120: Went through all the data types in the DLL and NumGet and matched them up to MSDN which fixed IDcmd.
; Update 20160308: Fix for Windows 10 NotifyIconOverflowWindow
; Update 20180313: Fix problem with "VirtualFreeEx" pointed out by nnnik
; Update 20180313: Additional fix for previous Windows 10 NotifyIconOverflowWindow fix breaking non-hidden icons
; ----------------------------------------------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------------------------------------------
; Function ......: TrayIcon_GetInfo
; Description ...: Get a series of useful information about tray icons.
; Parameters ....: sExeName - The exe for which we are searching the tray icon data. Leave it empty to receive data for
; ...............: all tray icons.
; Return ........: oTrayIcon_GetInfo - An array of objects containing tray icons data. Any entry is structured like this:
; ...............: oTrayIcon_GetInfo[A_Index].idx - 0 based tray icon index.
; ...............: oTrayIcon_GetInfo[A_Index].IDcmd - Command identifier associated with the button.
; ...............: oTrayIcon_GetInfo[A_Index].pID - Process ID.
; ...............: oTrayIcon_GetInfo[A_Index].uID - Application defined identifier for the icon.
; ...............: oTrayIcon_GetInfo[A_Index].msgID - Application defined callback message.
; ...............: oTrayIcon_GetInfo[A_Index].hIcon - Handle to the tray icon.
; ...............: oTrayIcon_GetInfo[A_Index].hWnd - Window handle.
; ...............: oTrayIcon_GetInfo[A_Index].Class - Window class.
; ...............: oTrayIcon_GetInfo[A_Index].Process - Process executable.
; ...............: oTrayIcon_GetInfo[A_Index].Tray - Tray Type (Shell_TrayWnd or NotifyIconOverflowWindow).
; ...............: oTrayIcon_GetInfo[A_Index].tooltip - Tray icon tooltip.
; Info ..........: TB_BUTTONCOUNT message - http://goo.gl/DVxpsg
; ...............: TB_GETBUTTON message - http://goo.gl/2oiOsl
; ...............: TBBUTTON structure - http://goo.gl/EIE21Z
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetInfo(sExeName := "")
{
DetectHiddenWindows, % (Setting_A_DetectHiddenWindows := A_DetectHiddenWindows) ? "On" :
oTrayIcon_GetInfo := {}
For key, sTray in ["Shell_TrayWnd", "NotifyIconOverflowWindow"]
{
idxTB := TrayIcon_GetTrayBar(sTray)
WinGet, pidTaskbar, PID, ahk_class %sTray%
hProc := DllCall("OpenProcess", UInt, 0x38, Int, 0, UInt, pidTaskbar)
pRB := DllCall("VirtualAllocEx", Ptr, hProc, Ptr, 0, UPtr, 20, UInt, 0x1000, UInt, 0x4)
SendMessage, 0x418, 0, 0, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_BUTTONCOUNT
szBtn := VarSetCapacity(btn, (A_Is64bitOS ? 32 : 20), 0)
szNfo := VarSetCapacity(nfo, (A_Is64bitOS ? 32 : 24), 0)
szTip := VarSetCapacity(tip, 128 * 2, 0)
Loop, %ErrorLevel%
{
SendMessage, 0x417, A_Index - 1, pRB, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_GETBUTTON
DllCall("ReadProcessMemory", Ptr, hProc, Ptr, pRB, Ptr, &btn, UPtr, szBtn, UPtr, 0)
iBitmap := NumGet(btn, 0, "Int")
IDcmd := NumGet(btn, 4, "Int")
statyle := NumGet(btn, 8)
dwData := NumGet(btn, (A_Is64bitOS ? 16 : 12))
iString := NumGet(btn, (A_Is64bitOS ? 24 : 16), "Ptr")
DllCall("ReadProcessMemory", Ptr, hProc, Ptr, dwData, Ptr, &nfo, UPtr, szNfo, UPtr, 0)
hWnd := NumGet(nfo, 0, "Ptr")
uID := NumGet(nfo, (A_Is64bitOS ? 8 : 4), "UInt")
msgID := NumGet(nfo, (A_Is64bitOS ? 12 : 8))
hIcon := NumGet(nfo, (A_Is64bitOS ? 24 : 20), "Ptr")
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, UPtr, szTip, UPtr, 0)
Index := (oTrayIcon_GetInfo.MaxIndex()>0 ? oTrayIcon_GetInfo.MaxIndex()+1 : 1)
oTrayIcon_GetInfo[Index,"idx"] := A_Index - 1
oTrayIcon_GetInfo[Index,"IDcmd"] := IDcmd
oTrayIcon_GetInfo[Index,"pID"] := pID
oTrayIcon_GetInfo[Index,"uID"] := uID
oTrayIcon_GetInfo[Index,"msgID"] := msgID
oTrayIcon_GetInfo[Index,"hIcon"] := hIcon
oTrayIcon_GetInfo[Index,"hWnd"] := hWnd
oTrayIcon_GetInfo[Index,"Class"] := sClass
oTrayIcon_GetInfo[Index,"Process"] := sProcess
oTrayIcon_GetInfo[Index,"Tooltip"] := StrGet(&tip, "UTF-16")
oTrayIcon_GetInfo[Index,"Tray"] := sTray
}
}
DllCall("VirtualFreeEx", Ptr, hProc, Ptr, pRB, UPtr, 0, Uint, 0x8000)
DllCall("CloseHandle", Ptr, hProc)
}
DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
Return oTrayIcon_GetInfo
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Hide
; Description ..: Hide or unhide a tray icon.
; Parameters ...: IDcmd - Command identifier associated with the button.
; ..............: bHide - True for hide, False for unhide.
; ..............: sTray - 1 or Shell_TrayWnd || 0 or NotifyIconOverflowWindow.
; Info .........: TB_HIDEBUTTON message - http://goo.gl/oelsAa
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Hide(IDcmd, sTray := "Shell_TrayWnd", bHide:=True)
{
(sTray == 0 ? sTray := "NotifyIconOverflowWindow" : sTray == 1 ? sTray := "Shell_TrayWnd" : )
DetectHiddenWindows, % (Setting_A_DetectHiddenWindows := A_DetectHiddenWindows) ? "On" :
idxTB := TrayIcon_GetTrayBar()
SendMessage, 0x404, IDcmd, bHide, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_HIDEBUTTON
SendMessage, 0x1A, 0, 0, , ahk_class %sTray%
DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Delete
; Description ..: Delete a tray icon.
; Parameters ...: idx - 0 based tray icon index.
; ..............: sTray - 1 or Shell_TrayWnd || 0 or NotifyIconOverflowWindow.
; Info .........: TB_DELETEBUTTON message - http://goo.gl/L0pY4R
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Delete(idx, sTray := "Shell_TrayWnd")
{
(sTray == 0 ? sTray := "NotifyIconOverflowWindow" : sTray == 1 ? sTray := "Shell_TrayWnd" : )
DetectHiddenWindows, % (Setting_A_DetectHiddenWindows := A_DetectHiddenWindows) ? "On" :
idxTB := TrayIcon_GetTrayBar()
SendMessage, 0x416, idx, 0, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_DELETEBUTTON
SendMessage, 0x1A, 0, 0, , ahk_class %sTray%
DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Remove
; Description ..: Remove a tray icon.
; Parameters ...: hWnd, uID.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Remove(hWnd, uID)
{
NumPut(VarSetCapacity(NID,(A_IsUnicode ? 2 : 1) * 384 + A_PtrSize * 5 + 40,0), NID)
NumPut(hWnd , NID, (A_PtrSize == 4 ? 4 : 8 ))
NumPut(uID , NID, (A_PtrSize == 4 ? 8 : 16 ))
Return DllCall("shell32\Shell_NotifyIcon", "Uint", 0x2, "Uint", &NID)
}
; ----------------------------------------------------------------------------------------------------------------------
; 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.
; ..............: sTray - 1 or Shell_TrayWnd || 0 or NotifyIconOverflowWindow.
; Info .........: TB_MOVEBUTTON message - http://goo.gl/1F6wPw
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Move(idxOld, idxNew, sTray := "Shell_TrayWnd")
{
(sTray == 0 ? sTray := "NotifyIconOverflowWindow" : sTray == 1 ? sTray := "Shell_TrayWnd" : )
DetectHiddenWindows, % (Setting_A_DetectHiddenWindows := A_DetectHiddenWindows) ? "On" :
idxTB := TrayIcon_GetTrayBar()
SendMessage, 0x452, idxOld, idxNew, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_MOVEBUTTON
DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetTrayBar
; Description ..: Get the tray icon handle.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetTrayBar(Tray:="Shell_TrayWnd")
{
DetectHiddenWindows, % (Setting_A_DetectHiddenWindows := A_DetectHiddenWindows) ? "On" :
WinGet, ControlList, ControlList, ahk_class %Tray%
RegExMatch(ControlList, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", nTB)
Loop, %nTB%
{
ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class %Tray%
hParent := DllCall( "GetParent", Ptr, hWnd )
WinGetClass, sClass, ahk_id %hParent%
If !(sClass = "SysPager" or sClass = "NotifyIconOverflowWindow" )
Continue
idxTB := A_Index
Break
}
DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
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
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Button
; Description ..: Simulate mouse button click on a tray icon.
; Parameters ...: sExeName - Executable Process Name of tray icon.
; ..............: sButton - Mouse button to simulate (L, M, R).
; ..............: bDouble - True to double click, false to single click.
; ..............: index - Index of tray icon to click if more than one match.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Button(sExeName, sButton := "L", bDouble := false, index := 1)
{
DetectHiddenWindows, % (Setting_A_DetectHiddenWindows := A_DetectHiddenWindows) ? "On" :
WM_MOUSEMOVE = 0x0200
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_LBUTTONDBLCLK = 0x0203
WM_RBUTTONDOWN = 0x0204
WM_RBUTTONUP = 0x0205
WM_RBUTTONDBLCLK = 0x0206
WM_MBUTTONDOWN = 0x0207
WM_MBUTTONUP = 0x0208
WM_MBUTTONDBLCLK = 0x0209
sButton := "WM_" sButton "BUTTON"
oIcons := {}
oIcons := TrayIcon_GetInfo(sExeName)
msgID := oIcons[index].msgID
uID := oIcons[index].uID
hWnd := oIcons[index].hWnd
if bDouble
PostMessage, msgID, uID, %sButton%DBLCLK, , ahk_id %hWnd%
else
{
PostMessage, msgID, uID, %sButton%DOWN, , ahk_id %hWnd%
PostMessage, msgID, uID, %sButton%UP, , ahk_id %hWnd%
}
DetectHiddenWindows, %Setting_A_DetectHiddenWindows%
return
}