[LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
cyruz
Posts: 345
Joined: 30 Sep 2013, 13:31

[LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

31 Dec 2013, 15:04

Hi guys,
I tried to fix the incompatibility of Sean's old TrayIcon library with AutoHotkey Unicode 32 and 64 bit.

Looks like it's working but I had some problem with the dwData field of the TBBUTTON structure, that is undocumented. If you find any inconsistency related to the "hWnd", "uID", "nMsg" and "hIcon" variables in the TrayIcon_GetInfo function, please provide some info.

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------
; Name ..........: TrayIcon library
; Description ...: Provide some useful functions to deal with Tray icons.
; AHK Version ...: AHK_L 1.1.22.02 x32/64 Unicode
; Code from .....: Sean (http://www.autohotkey.com/forum/viewtopic.php?t=17314)
; Author ........: Cyruz (http://ciroprincipe.info) (http://ahkscript.org/boards/viewtopic.php?f=6&t=1229)
; Mod from ......: Fanatic Guru - Cyruz
; License .......: WTFPL - http://www.wtfpl.net/txt/copying/
; Version Date ..: 2019.03.12
; Upd.20160120 ..: Fanatic Guru - Went through all the data types in the DLL and NumGet and matched them up to MSDN
; ...............:                which fixed idCmd.
; Upd.20160308 ..: Fanatic Guru - Fix for Windows 10 NotifyIconOverflowWindow.
; Upd.20180313 ..: Fanatic Guru - Fix problem with "VirtualFreeEx" pointed out by nnnik.
; Upd.20180313 ..: Fanatic Guru - Additional fix for previous Windows 10 NotifyIconOverflowWindow fix breaking non
; ...............:                hidden icons.
; Upd.20190312 ..: Cyruz        - Added TrayIcon_Set, code merged and refactored.
; ----------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------
; 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 ........: oTrayInfo - An array of objects containing tray icons data. Any entry is structured like this:
; ...............:             oTrayInfo[A_Index].idx     - 0 based tray icon index.
; ...............:             oTrayInfo[A_Index].idcmd   - Command identifier associated with the button.
; ...............:             oTrayInfo[A_Index].pid     - Process ID.
; ...............:             oTrayInfo[A_Index].uid     - Application defined identifier for the icon.
; ...............:             oTrayInfo[A_Index].msgid   - Application defined callback message.
; ...............:             oTrayInfo[A_Index].hicon   - Handle to the tray icon.
; ...............:             oTrayInfo[A_Index].hwnd    - Window handle.
; ...............:             oTrayInfo[A_Index].class   - Window class.
; ...............:             oTrayInfo[A_Index].process - Process executable.
; ...............:             oTrayInfo[A_Index].tray    - Tray Type (Shell_TrayWnd or NotifyIconOverflowWindow).
; ...............:             oTrayInfo[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 := "")
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On

    oTrayInfo := []
    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,0x04)

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

        ; TB_BUTTONCOUNT = 0x0418
        SendMessage, 0x0418, 0, 0, ToolbarWindow32%idxTB%, ahk_class %sTray%
        Loop, %ErrorLevel%
        {
             ; TB_GETBUTTON 0x0417
            SendMessage, 0x0417, A_Index-1, pRB, ToolbarWindow32%idxTB%, ahk_class %sTray%

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

            iBitmap := NumGet(btn, 0, "Int")
            idCmd   := NumGet(btn, 4, "Int")
            fsState := NumGet(btn, 8, "UChar")
            fsStyle := NumGet(btn, 9, "UChar")
            dwData  := NumGet(btn, (A_Is64bitOS ? 16 : 12), "UPtr")
            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), "UPtr")
            hIcon := NumGet(nfo, (A_Is64bitOS ? 24 : 20), "Ptr")

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

            If ( !sExeName || sExeName == sProcess || sExeName == nPid )
            {
                DllCall("ReadProcessMemory", Ptr,hProc, Ptr,iString, Ptr,&tip, UPtr,szTip, UPtr,0)
                oTrayInfo.Push({ "idx"     : A_Index-1
                               , "idcmd"   : idCmd
                               , "pid"     : nPid
                               , "uid"     : uId
                               , "msgid"   : msgId
                               , "hicon"   : hIcon
                               , "hwnd"    : hWnd
                               , "class"   : sClass
                               , "process" : sProcess
                               , "tooltip" : StrGet(&tip, "UTF-16")
                               , "tray"    : sTray })
            }
        }
        DllCall("VirtualFreeEx", Ptr,hProc, Ptr,pRB, UPtr,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.
; ..............: sTray - 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, sTray:="Shell_TrayWnd", bHide:=True)
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x0404, idCmd, bHide, ToolbarWindow32%idxTB%, ahk_class %sTray% ; TB_HIDEBUTTON
    SendMessage, 0x001A, 0, 0, , ahk_class %sTray%
    DetectHiddenWindows, %d%
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Delete
; Description ..: Delete a tray icon.
; Parameters ...: idx   - 0 based tray icon index.
; ..............: sTray - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
; Info .........: TB_DELETEBUTTON message - http://goo.gl/L0pY4R
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Delete(idx, sTray:="Shell_TrayWnd")
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x0416, idx, 0, ToolbarWindow32%idxTB%, ahk_class %sTrayPlace% ; TB_DELETEBUTTON = 0x0416
    SendMessage, 0x001A, 0, 0, , ahk_class %sTrayPlace%
    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.
; Info .........: NOTIFYICONDATA structure  - https://goo.gl/1Xuw5r
; ..............: Shell_NotifyIcon function - https://goo.gl/tTSSBM
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Remove(hWnd, uId)
{
        VarSetCapacity(NID, szNID := ((A_IsUnicode ? 2 : 1) * 384 + A_PtrSize*5 + 40),0)
        NumPut( szNID, NID, 0           )
        NumPut( hWnd,  NID, A_PtrSize   )
        NumPut( uId,   NID, A_PtrSize*2 )
        Return DllCall("Shell32.dll\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  - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
; Info .........: TB_MOVEBUTTON message - http://goo.gl/1F6wPw
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Move(idxOld, idxNew, sTray := "Shell_TrayWnd")
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x452, idxOld, idxNew, ToolbarWindow32%idxTB%, ahk_class %sTrayPlace% ; TB_MOVEBUTTON = 0x452
    DetectHiddenWindows, %d%
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Set
; Description ..: Modify icon with the given index for the given window.
; Parameters ...: hWnd       - Window handle.
; ..............: uId        - Application defined identifier for the icon.
; ..............: hIcon      - Handle to the tray icon.
; ..............: hIconSmall - Handle to the small icon, for window menubar. Optional.
; ..............: hIconBig   - Handle to the big icon, for taskbar. Optional.
; Return .......: True on success, false on failure.
; Info .........: NOTIFYICONDATA structure  - https://goo.gl/1Xuw5r
; ..............: Shell_NotifyIcon function - https://goo.gl/tTSSBM
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Set(hWnd, uId, hIcon, hIconSmall:=0, hIconBig:=0)
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    ; WM_SETICON = 0x0080
    If ( hIconSmall ) 
        SendMessage, 0x0080, 0, hIconSmall,, ahk_id %hWnd%
    If ( hIconBig )
        SendMessage, 0x0080, 1, hIconBig,, ahk_id %hWnd%
    DetectHiddenWindows, %d%

    VarSetCapacity(NID, szNID := ((A_IsUnicode ? 2 : 1) * 384 + A_PtrSize*5 + 40),0)
    NumPut( szNID, NID, 0                           )
    NumPut( hWnd,  NID, (A_PtrSize == 4) ? 4   : 8  )
    NumPut( uId,   NID, (A_PtrSize == 4) ? 8   : 16 )
    NumPut( 2,     NID, (A_PtrSize == 4) ? 12  : 20 )
    NumPut( hIcon, NID, (A_PtrSize == 4) ? 20  : 32 )
    
    ; NIM_MODIFY := 0x1
    Return DllCall("Shell32.dll\Shell_NotifyIcon", UInt,0x1, Ptr,&NID)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetTrayBar
; Description ..: Get the tray icon handle.
; Parameters ...: sTray - Traybar to retrieve.
; Return .......: Tray icon handle.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetTrayBar(sTray:="Shell_TrayWnd")
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    WinGet, ControlList, ControlList, ahk_class %sTray%
    RegExMatch(ControlList, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", nTB)
    Loop, %nTB%
    {
        ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class %sTray%
        hParent := DllCall( "GetParent", Ptr, hWnd )
        WinGetClass, sClass, ahk_id %hParent%
        If !(sClass == "SysPager" || sClass == "NotifyIconOverflowWindow" )
            Continue
        idxTB := A_Index
        Break
    }
    DetectHiddenWindows, %d%
    Return idxTB
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetHotItem
; Description ..: Get the index of tray's hot item.
; Return .......: Index of tray's hot item.
; Info .........: TB_GETHOTITEM message - http://goo.gl/g70qO2
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetHotItem()
{
    idxTB := TrayIcon_GetTrayBar()
    SendMessage, 0x0447, 0, 0, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd ; TB_GETHOTITEM = 0x0447
    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.
; ..............: nIdx     - Index of tray icon to click if more than one match.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Button(sExeName, sButton:="L", bDouble:=False, nIdx:=1)
{
    d := A_DetectHiddenWindows
    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  := TrayIcon_GetInfo(sExeName)
    If ( bDouble )
        PostMessage, oIcons[nIdx].msgid, oIcons[nIdx].uid, %sButton%DBLCLK,, % "ahk_id " oIcons[nIdx].hwnd
    Else
    {
        PostMessage, oIcons[nIdx].msgid, oIcons[nIdx].uid, %sButton%DOWN,, % "ahk_id " oIcons[nIdx].hwnd
        PostMessage, oIcons[nIdx].msgid, oIcons[nIdx].uid, %sButton%UP,, % "ahk_id " oIcons[nIdx].hwnd
    }
    DetectHiddenWindows, %d%
    Return
}
Some test code:

Code: Select all

test := TrayIcon_GetInfo()
Loop, % test.MaxIndex()
    str .= test[A_Index].place " - " test[A_Index].idx " - " test[A_Index].process " - " test[A_Index].hwnd " - " test[A_Index].idcmd "`n"
MsgBox, %str%

*** UPDATE ***

2019-03-12 :: Code merged with all the changes implemented by FanaticGuru and RiseUp. Added the function TrayIcon_Set.


*** IMPORTANT ***

FanaticGuru's version: https://autohotkey.com/boards/viewtopic.php?p=9186#p9186
RiseUp's version: https://autohotkey.com/boards/viewtopic.php?p=184685#p184685
Last edited by cyruz on 03 Apr 2019, 21:57, edited 6 times in total.
ABCza on the old forum.
My GitHub.
User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

31 Dec 2013, 18:28

Below is a link to one of my scripts that uses an updated version of TrayIcon.

Script with Updated TrayIcon

It seems to work for Ansi and Unicode 32 bit but not for Unicode 64 bit.

I also changed it to return results as an object instead of a string with delimiters which it looks like you did also.

TrayIcon is a really useful group of functions. Great job updating it for Unicode 64 bit.

I am going to play around with your TrayIcon and see if I can use it in place of my version.

Too bad you did not do this sooner. It took me forever to get a working version of TrayIcon!

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
User avatar
cyruz
Posts: 345
Joined: 30 Sep 2013, 13:31

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

31 Dec 2013, 19:38

FanaticGuru wrote:Below is a link to one of my scripts that uses an updated version of TrayIcon.

Script with Updated TrayIcon

It seems to work for Ansi and Unicode 32 bit but not for Unicode 64 bit.

I also changed it to return results as an object instead of a string with delimiters which it looks like you did also.

TrayIcon is a really useful group of functions. Great job updating it for Unicode 64 bit.

I am going to play around with your TrayIcon and see if I can use it in place of my version.

Too bad you did not do this sooner. It took me forever to get a working version of TrayIcon!

FG
Yeah I worked on it because I need in one of my script too... Really a nice piece of code.
ABCza on the old forum.
My GitHub.
User avatar
Chef
Posts: 50
Joined: 14 Nov 2013, 13:01

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

01 Jan 2014, 05:05

Worked on this too, I think some functions could be better tweaked to work with handles instead of index.
here is my version...
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

14 Jan 2014, 19:48

cyruz wrote:Hi guys,
I tried to fix the incompatibility of Sean's old TrayIcon library with AutoHotkey Unicode 32 and 64 bit.
Can you give an example of how to get some information using this script, please. I'm using Windows 7, 64 bit and tried:

Code: Select all

    test := TrayIcon_GetInfo()
	msgbox  %test%
But nothing was displayed in the msgbox
User avatar
Chef
Posts: 50
Joined: 14 Nov 2013, 13:01

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 03:20

That's because info is being stored in an array, you can't messageBox it like that, you need a for loop.
Look at my code above.
User avatar
cyruz
Posts: 345
Joined: 30 Sep 2013, 13:31

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 06:35

PuzzledGreatly wrote:
cyruz wrote:Hi guys,
I tried to fix the incompatibility of Sean's old TrayIcon library with AutoHotkey Unicode 32 and 64 bit.
Can you give an example of how to get some information using this script, please. I'm using Windows 7, 64 bit and tried:

Code: Select all

    test := TrayIcon_GetInfo()
	msgbox  %test%
But nothing was displayed in the msgbox
As Chef already said, you should loop the array, because the function returns an array of objects:

Code: Select all

test := TrayIcon_GetInfo()
Loop % test.MaxIndex()
    MsgBox, % test[A_Index].process
You can extract all the other properties. Just look at the function description.
ABCza on the old forum.
My GitHub.
User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 14:49

I merged my version of an update to Sean's TrayIcon with Cyruz's update to 64 bit. My version did not work for Unicode64 and Cyruz did a great job on commenting.

The main additions to Cyruz's work is:
  • handling of the NotifyIconOverflowWindow in addition to the Shell_TrayWnd
  • addition of TrayIcon_Remove updated to handle Ansi, Unicode32, Unicode64 versions of AHK
  • functions restore DetectHiddenWindows state to its original settings before returning
  • some superficial changes in coding style and naming conventions
  • included some example code showing usage of TrayIcon_GetInfo
  • addition of TrayIcon_Button to simulate mouse button clicks of Tray Icons
  • updated 2016/01/20 to fix some data type issues that were effecting IDcmd
  • updated 2016/03/08 to handle Windows 10 NotifyIconOverflowWindow better
  • updated 2018/03/13 to fix problem with "VirtualFreeEx" pointed out by nnnik
  • updated 2018/03/13 for additional fix for previous Windows 10 NotifyIconOverflowWindow fix breaking non-hidden icons
  • updated 2019/04/04 addition of TrayIcon_Set by Cyruz

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------
; 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...: 2019 04 04
; 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
; Update 20190404: Added TrayIcon_Set by Cyruz
; ----------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------
; 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_Set
; Description ..: Modify icon with the given index for the given window.
; Parameters ...: hWnd       - Window handle.
; ..............: uId        - Application defined identifier for the icon.
; ..............: hIcon      - Handle to the tray icon.
; ..............: hIconSmall - Handle to the small icon, for window menubar. Optional.
; ..............: hIconBig   - Handle to the big icon, for taskbar. Optional.
; Return .......: True on success, false on failure.
; Info .........: NOTIFYICONDATA structure  - https://goo.gl/1Xuw5r
; ..............: Shell_NotifyIcon function - https://goo.gl/tTSSBM
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Set(hWnd, uId, hIcon, hIconSmall:=0, hIconBig:=0)
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows, On
    ; WM_SETICON = 0x0080
    If ( hIconSmall ) 
        SendMessage, 0x0080, 0, hIconSmall,, ahk_id %hWnd%
    If ( hIconBig )
        SendMessage, 0x0080, 1, hIconBig,, ahk_id %hWnd%
    DetectHiddenWindows, %d%

    VarSetCapacity(NID, szNID := ((A_IsUnicode ? 2 : 1) * 384 + A_PtrSize*5 + 40),0)
    NumPut( szNID, NID, 0                           )
    NumPut( hWnd,  NID, (A_PtrSize == 4) ? 4   : 8  )
    NumPut( uId,   NID, (A_PtrSize == 4) ? 8   : 16 )
    NumPut( 2,     NID, (A_PtrSize == 4) ? 12  : 20 )
    NumPut( hIcon, NID, (A_PtrSize == 4) ? 20  : 32 )
    
    ; NIM_MODIFY := 0x1
    Return DllCall("Shell32.dll\Shell_NotifyIcon", UInt,0x1, Ptr,&NID)
}

; ----------------------------------------------------------------------------------------------------------------------
; 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
}
FG
Last edited by FanaticGuru on 04 Apr 2019, 14:03, edited 9 times in total.
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
HomePlayer
Posts: 9
Joined: 09 Jan 2014, 08:01

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 17:48

Hey,

would you pls describe what it is does?
User avatar
cyruz
Posts: 345
Joined: 30 Sep 2013, 13:31

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 19:22

FanaticGuru wrote:I merged my version of an update to Sean's TrayIcon with Cyruz's update to 64 bit...
Thank you FanaticGuru. I merged some of your modifications in my code. I will reference your post in the OP.
ABCza on the old forum.
My GitHub.
User avatar
cyruz
Posts: 345
Joined: 30 Sep 2013, 13:31

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 19:24

HomePlayer wrote:Hey,

would you pls describe what it is does?
There is a description for every function in the code :)
It's a library to deal with tray icons (get info, move, delete, hide).
Last edited by cyruz on 15 Jan 2014, 20:29, edited 1 time in total.
ABCza on the old forum.
My GitHub.
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 19:59

Thanks for the updated version. I follow about the array but still can't simulate a right-click. For an example I tried uncommenting the example and ended up with this:

Code: Select all

    oIcons := {}
    oIcons := TrayIcon_GetInfo("WinPatrol.exe")

    for index, element in oIcons
        sInfoDisplay .= "idx: " element.idx " | cmdID: " element.cmdID " | pID: " element.pID " | uID: " element.uID " | msgID: " element.msgID " | hIcon: " element.hIcon " | hWnd: " element.hWnd " | Class: " element.Class " | Process: " element.Process " | Tray: " element.Tray " | Tooltip: " element.Tooltip "`n`n"

    MsgBox %sInfoDisplay%

    ; Button Example:
    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

    PostMessage, MsgID, uID, WM_RBUTTONDOWN, , ahk_id %hWnd%
    PostMessage, MsgID, uID, WM_RBUTTONUP  , , ahk_id %hWnd%
I'm seeing the msgbox populated as expected but no right-click. I've tried various combinations with PostMessage without success. How to make it work?
User avatar
cyruz
Posts: 345
Joined: 30 Sep 2013, 13:31

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 20:38

PuzzledGreatly wrote:Thanks for the updated version. I follow about the array but still can't simulate a right-click. For an example I tried uncommenting the example and ended up with this:

Code: Select all

    oIcons := {}
    oIcons := TrayIcon_GetInfo("WinPatrol.exe")

    for index, element in oIcons
        sInfoDisplay .= "idx: " element.idx " | cmdID: " element.cmdID " | pID: " element.pID " | uID: " element.uID " | msgID: " element.msgID " | hIcon: " element.hIcon " | hWnd: " element.hWnd " | Class: " element.Class " | Process: " element.Process " | Tray: " element.Tray " | Tooltip: " element.Tooltip "`n`n"

    MsgBox %sInfoDisplay%

    ; Button Example:
    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

    PostMessage, MsgID, uID, WM_RBUTTONDOWN, , ahk_id %hWnd%
    PostMessage, MsgID, uID, WM_RBUTTONUP  , , ahk_id %hWnd%
I'm seeing the msgbox populated as expected but no right-click. I've tried various combinations with PostMessage without success. How to make it work?
I didn't know about the possibility to simulate a right click with this library, that seems the example FanaticGuru provided in his code. You cannot pass %hWnd% to the PostMessage without initializing the variable first... In the for loop you need something like:

Code: Select all

hWnd := element.hWnd
Anyway I suggest that you read the array documentation. You will need it to work with this library.
ABCza on the old forum.
My GitHub.
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

15 Jan 2014, 22:00

cyruz wrote:
I didn't know about the possibility to simulate a right click with this library, that seems the example FanaticGuru provided in his code. You cannot pass %hWnd% to the PostMessage without initializing the variable first... In the for loop you need something like:

Code: Select all

hWnd := element.hWnd
Anyway I suggest that you read the array documentation. You will need it to work with this library.
Arh! Yes, I see. Thanks for pointing that out.
User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

16 Jan 2014, 16:29

PuzzledGreatly wrote:Thanks for the updated version. I follow about the array but still can't simulate a right-click. For an example I tried uncommenting the example and ended up with this:
I made a function for tray icon mouse button clicking that should make it easier for you.

Code: Select all

; Example:
TrayIcon_Button("steam.exe", "R")	

; ----------------------------------------------------------------------------------------------------------------------
; 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)
{
	Setting_A_DetectHiddenWindows := A_DetectHiddenWindows
	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
}

#Include [Library] TrayIcon.ahk
FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

16 Jan 2014, 18:53

That's great - thank you very much.
magusneo
Posts: 45
Joined: 30 Sep 2013, 06:34

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

02 Aug 2014, 08:10

Thanks.But it seems there is no TrayIcon can work with SetTrayIcon().
User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

04 Aug 2014, 13:31

magusneo wrote:Thanks.But it seems there is no TrayIcon can work with SetTrayIcon().
As best as I can tell, Sean's TrayIcon Library did not included SetTrayIcon. Even though it has TrayIcon in the name the library was all commands that started with TrayIcon_.

If it was part of the library it should be named TrayIcon_Set. This is more than just schematics as a library must have this naming convention to be used as a library by AHK.

All that aside it would be nice to add TrayIcon_Set. I might look at what it would take to add it but at first glance I am not familiar with everything it is doing and what would need to change to make it work with 64 bit.

Here are the two versions I have:

Code: Select all

SetTrayIcon( Gui0=0 ) {
 Hex := "W1Y1Z10101X1Y4Z2801X16V28V1U2T1Y4RCKMFF9C9CZFFA2A2ZFFAAAAZFFB0BYFFB4B4ZFFBABAZFF"
 . "BFBFZFFC4C4ZFFCACAZFFD1D1ZFFD6D6ZFFDDDDZFFE4E4ZFFEBEBZFFFFFFKWBDVCEVADVCEV9DVCEV7BVCE"
 . "V5AVCDV37ABA988ACV246765458AV13V58V12V37V12V25V12V24V22V23KYFFFFXC3C3XC3C3XC3C3XC3C3X"
 . "C3C3XCZ3XCZ3XCZ3XCZ3XC3C3XC3C3XC3C3XC3C3XC3C3XFFFFX"
 VarSetCapacity(Z,512,48), Nums:="512|256|128|64|32|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2"
 Loop, Parse, Nums, |                                  ;  uncompressing nulls in hex data
  StringReplace,hex,hex,% Chr(70+A_Index),% SubStr(Z,1,A_LoopField),All
 VarSetCapacity( IconData,( nSize:=StrLen(Hex)//2) )
 Loop %nSize%
   NumPut( "0x" . SubStr(Hex,2*A_Index-1,2), IconData, A_Index-1, "Char" )
 hICon := DllCall( "CreateIconFromResourceEx", UInt,&IconData+22, UInt,0, Int,1
                   ,UInt,196608, Int,16, Int,16, UInt,0 )
 PID := DllCall("GetCurrentProcessId"), VarSetCapacity( NID,444,0 ), NumPut( 444,NID )
 NumPut( Gui0,NID,4 ), NumPut( 1028,NID,8 ), NumPut( 2,NID,12 ), NumPut( hIcon,NID,20 )
 Menu, Tray, Icon,,, 1
 DllCall( "shell32\Shell_NotifyIcon", UInt,0x1, UInt,&NID )
}

Code: Select all

; Thanks SKAN               - http://www.autohotkey.com/forum/viewtopic.php?t=33955
SetTrayIcon(ByRef IconDataHex) {
  VarSetCapacity(IconData, (nSize:=StrLen(IconDataHex)//2))
  Loop %nSize% ; MCode by Laszlo Hars: http://www.autohotkey.com/forum/viewtopic.php?t=21172
    NumPut("0x" . SubStr(IconDataHex, 2*A_Index - 1, 2), IconData, A_Index-1, "UChar")
  IconDataHex := ""

  hICon := DllCall( "User32.dll\CreateIconFromResourceEx"
                    , UInt, &IconData+22
                    , UInt, NumGet(IconData, 14)
                    , Int, 1
                    , UInt, 0x00030000
                    , Int, 16
                    , Int, 16
                    , UInt, 0 )

  ; Thanks Chris            - http://www.autohotkey.com/forum/viewtopic.php?p=69461#69461
  Gui +LastFound
  SendMessage, (WM_SETICON:=0x80), 0, hIcon ; Set the Titlebar Icon
  SendMessage, (WM_SETICON:=0x80), 1, hIcon ; Set the Alt-Tab icon

  ; Creating NOTIFYICONDATA - http://www.msdn.microsoft.com/en-us/library/aa930660.aspx
  ; Thanks Lexikos          - http://www.autohotkey.com/forum/viewtopic.php?p=162175#162175
  VarSetCapacity(NID, 444, 0)
  NumPut(444, NID, 0)
  DetectHiddenWindows, On
  NumPut(WinExist(A_ScriptFullPath " ahk_class AutoHotkey ahk_pid " DllCall("GetCurrentProcessId")), NID, 4)
  DetectHiddenWindows, Off
  NumPut(1028, NID, 8)
  NumPut(2, NID, 12)
  NumPut(hIcon, NID, 20)

  Return DllCall( "Shell32.dll\Shell_NotifyIcon"
                  , UInt, 0x1
                  , UInt, &NID )
FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
kidbit
Posts: 168
Joined: 02 Oct 2013, 16:05

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

25 Oct 2014, 13:07

FG, what's the difference between TrayIcon_Remove and TrayIcon_Delete?
Also, what is 'Command identifier associated with the button (cmdID)'?
question := (2b) || !(2b) © Shakespeare.
User avatar
FanaticGuru
Posts: 1905
Joined: 30 Sep 2013, 22:25

Re: [LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit

25 Oct 2014, 23:25

kidbit wrote:FG, what's the difference between TrayIcon_Remove and TrayIcon_Delete?
Also, what is 'Command identifier associated with the button (cmdID)'?
I believe TrayIcon_Remove and TrayIcon_Delete both end up doing the same thing by different means. One uses SendMessage to get it done the other uses a DLL call to get it done.

The main difference to the user is Delete uses the tray index which is prone to changing while Remove uses the uID which tends to be more fixed.

cmdID, as I understand it, has to do with what command will do what to the button. I have never used it but it is part of Windows' structure of a tray icon so it's value is reported by the function.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: KnIfER, TheNaviator and 88 guests