Sign in to follow this  
Followers 0

_SysTray UDF

52 posts in this topic

Posted (edited)

Here is my highly modified version of Tuape's UDF. The example shows how to get different info and how to remove dead icons (no mouse move required). I've included support for the Windows 7 NotifyIconOverflowWindow icons as well, however I recommend using my _OsVersionInfo UDF to determine the OS instead of @OSVersion. This should work on Win2000+, but some testers on XP and Vista would be appreciated.

_SysTray

#include-once
; ----------------------------------------------------------------------------
;
; Author:         Tuape
; Modified:       Erik Pilsits
;
; Script Function:
;   Systray UDF - Functions for reading icon info from system tray / removing
;   any icon.
;
; Last Update: 5/13/2013
;
; ----------------------------------------------------------------------------

;===============================================================================
;
; Function Name:    _SysTrayIconCount($iWin = 1)
; Description:      Returns number of icons on systray
;                   Note: Hidden icons are also reported
; Parameter(s):     $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Requirement(s):
; Return Value(s):  On Success - Returns number of icons found
;                   On Failure - Returns -1
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconCount($iWin = 1)
    Local Const $TB_BUTTONCOUNT = 1048
    Local $hWnd = _FindTrayToolbarWindow($iWin)
    If $hWnd = -1 Then Return -1
    Local $count = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $TB_BUTTONCOUNT, "wparam", 0, "lparam", 0)
    If @error Then Return -1
    Return $count[0]
EndFunc   ;==>_SysTrayIconCount

;===============================================================================
;
; Function Name:    _SysTrayIconTitles($iWin = 1)
; Description:      Get list of all window titles that have systray icon
; Parameter(s):     $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
; Requirement(s):
; Return Value(s):  On Success - Returns an array with all window titles
;                   On Failure - Returns -1
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconTitles($iWin = 1)
    Local $count = _SysTrayIconCount($iWin)
    If $count <= 0 Then Return -1
    Local $titles[$count]
    ; Get icon owner window"s title
    For $i = 0 To $count - 1
        $titles[$i] = WinGetTitle(_SysTrayIconHandle($i, $iWin))
    Next
    Return $titles
EndFunc   ;==>_SysTrayIconTitles

;===============================================================================
;
; Function Name:    _SysTrayIconPids($iWin = 1)
; Description:      Get list of all processes id's that have systray icon
; Parameter(s):     $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
; Requirement(s):
; Return Value(s):  On Success - Returns an array with all process id's
;                   On Failure - Returns -1
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconPids($iWin = 1)
    Local $count = _SysTrayIconCount($iWin)
    If $count <= 0 Then Return -1
    Local $processes[$count]
    For $i = 0 To $count - 1
        $processes[$i] = WinGetProcess(_SysTrayIconHandle($i, $iWin))
    Next
    Return $processes
EndFunc   ;==>_SysTrayIconPids

;===============================================================================
;
; Function Name:    _SysTrayIconProcesses($iWin = 1)
; Description:      Get list of all processes that have systray icon
; Parameter(s):     $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
; Requirement(s):
; Return Value(s):  On Success - Returns an array with all process names
;                   On Failure - Returns -1
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconProcesses($iWin = 1)
    Local $pids = _SysTrayIconPids($iWin)
    If Not IsArray($pids) Then Return -1
    Local $processes[UBound($pids)]
    ; List all processes
    Local $list = ProcessList()
    For $i = 0 To UBound($pids) - 1
        For $j = 1 To $list[0][0]
            If $pids[$i] = $list[$j][1] Then
                $processes[$i] = $list[$j][0]
                ExitLoop
            EndIf
        Next
    Next
    Return $processes
EndFunc   ;==>_SysTrayIconProcesses

;===============================================================================
;
; Function Name:    _SysTrayIconIndex($test, $mode = 0, $iWin = 1)
; Description:      Get list of all processes id"s that have systray icon
; Parameter(s):     $test       - process name / window title text / process PID
;                   $mode
;                   | 0         - get index by process name (default)
;                   | 1         - get index by window title
;                   | 2         - get index by process PID
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
; Requirement(s):
; Return Value(s):  On Success - Returns index of found icon
;                   On Failure - Returns -1
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconIndex($test, $mode = 0, $iWin = 1)
    Local $ret = -1, $compare = -1
    If $mode < 0 Or $mode > 2 Or Not IsInt($mode) Then Return -1
    Switch $mode
        Case 0
            $compare = _SysTrayIconProcesses($iWin)
        Case 1
            $compare = _SysTrayIconTitles($iWin)
        Case 2
            $compare = _SysTrayIconPids($iWin)
    EndSwitch
    If Not IsArray($compare) Then Return -1
    For $i = 0 To UBound($compare) - 1
        If $compare[$i] = $test Then
            $ret = $i
            ExitLoop
        EndIf
    Next
    Return $ret
EndFunc   ;==>_SysTrayIconIndex

; INTERNAL =====================================================================
;
; Function Name:    _SysTrayGetButtonInfo($iIndex, $iWin = 1, $iInfo = 0)
; Description:      Gets Tray Button Info
; Parameter(s):     $iIndex     - icon index (Note: starting from 0)
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;                   $iInfo      - Info to return
;                   | 1         - TBBUTTON structure
;                   | 2         - TRAYDATA structure
;                   | 3         - tooltip
;                   | 4         - icon position
; Requirement(s):
; Return Value(s):  On Success - Returns requested info
;                   On Failure - Sets @error and returns -1
;                   | 1        - Failed to find tray window
;                   | 2        - Failed to get tray window PID
;                   | 3        - Failed to open process
;                   | 4        - Failed to allocate memory
;                   | 5        - Failed to get TBBUTTON info
;
; Author(s):        Erik Pilsits, Tuape
;
;===============================================================================
Func _SysTrayGetButtonInfo($iIndex, $iWin = 1, $iInfo = 1)
    Local Const $TB_GETBUTTON = 1047
;~  Local Const $TB_GETBUTTONTEXT = 1099
;~  Local Const $TB_GETBUTTONINFO = 1089
    Local Const $TB_GETITEMRECT = 1053
    Local Const $ACCESS = BitOR(0x0008, 0x0010, 0x0400) ; VM_OPERATION, VM_READ, QUERY_INFORMATION
    Local $TBBUTTON
    If @OSArch = "X86" Then
        $TBBUTTON = DllStructCreate("int iBitmap;int idCommand;byte fsState;byte fsStyle;byte bReserved[2];dword dwData;int iString")
    Else ; X64
        $TBBUTTON = DllStructCreate("int iBitmap;int idCommand;byte fsState;byte fsStyle;byte bReserved[6];uint64 dwData;int64 iString")
    EndIf
    Local $TRAYDATA
    If @OSArch = "X86" Then
        $TRAYDATA = DllStructCreate("hwnd hwnd;uint uID;uint uCallbackMessage;dword Reserved[2];handle hIcon")
    Else
        $TRAYDATA = DllStructCreate("uint64 hwnd;uint uID;uint uCallbackMessage;dword Reserved[2];uint64 hIcon")
    EndIf
    Local $trayHwnd = _FindTrayToolbarWindow($iWin)
    If $trayHwnd = -1 Then Return SetError(1, 0, -1)
    Local $return, $err = 0
    Local $ret = DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $trayHwnd, "dword*", 0)
    If @error Or Not $ret[2] Then SetError(2, 0, -1)
    Local $pId = $ret[2]
    Local $procHandle = DllCall("kernel32.dll", "handle", "OpenProcess", "dword", $ACCESS, "bool", False, "dword", $pId)
    If @error Or Not $procHandle[0] Then Return SetError(3, 0, -1)
    Local $lpData = DllCall("kernel32.dll", "ptr", "VirtualAllocEx", "handle", $procHandle[0], "ptr", 0, "ulong", DllStructGetSize($TBBUTTON), "dword", 0x1000, "dword", 0x04)
    If Not @error And $lpData[0] Then
        $ret = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $trayHwnd, "uint", $TB_GETBUTTON, "wparam", $iIndex, "lparam", $lpData[0])
        If Not @error And $ret[0] Then
            DllCall("kernel32.dll", "bool", "ReadProcessMemory", "handle", $procHandle[0], "ptr", $lpData[0], "struct*", $TBBUTTON, "ulong", DllStructGetSize($TBBUTTON), "ulong*", 0)
            Switch $iInfo
                Case 2
                    ; TRAYDATA structure
                    DllCall("kernel32.dll", "bool", "ReadProcessMemory", "handle", $procHandle[0], "ptr", DllStructGetData($TBBUTTON, 6), "struct*", $TRAYDATA, "ulong", DllStructGetSize($TRAYDATA), "ulong*", 0)
                    $return = $TRAYDATA
                Case 3
                    ; tooltip
                    $return = ""
                    If BitShift(DllStructGetData($TBBUTTON, 7), 16) <> 0 Then
                        Local $intTip = DllStructCreate("wchar[1024]")
                        ; we have a pointer to a string, otherwise it is an internal resource identifier
                        DllCall("kernel32.dll", "bool", "ReadProcessMemory", "handle", $procHandle[0], "ptr", DllStructGetData($TBBUTTON, 7), "struct*", $intTip, "ulong", DllStructGetSize($intTip), "ulong*", 0)
                        $return = DllStructGetData($intTip, 1)
                    ;else internal resource
                    EndIf
                Case 4
                    ; icon position
                    If Not BitAND(DllStructGetData($TBBUTTON, 3), 8) Then ; 8 = TBSTATE_HIDDEN
                        Local $pos[2], $RECT = DllStructCreate("int;int;int;int")
                        DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $trayHwnd, "uint", $TB_GETITEMRECT, "wparam", $iIndex, "lparam", $lpData[0])
                        DllCall("kernel32.dll", "bool", "ReadProcessMemory", "handle", $procHandle[0], "ptr", $lpData[0], "struct*", $RECT, "ulong", DllStructGetSize($RECT), "ulong*", 0)
                        $ret = DllCall("user32.dll", "int", "MapWindowPoints", "hwnd", $trayHwnd, "ptr", 0, "struct*", $RECT, "uint", 2)
                        $pos[0] = DllStructGetData($RECT, 1)
                        $pos[1] = DllStructGetData($RECT, 2)
                        $return = $pos
                    Else
                        $return = -1
                    EndIf
                Case Else
                    ; TBBUTTON
                    $return = $TBBUTTON
            EndSwitch
        Else
            $err = 5
        EndIf
        DllCall("kernel32.dll", "bool", "VirtualFreeEx", "handle", $procHandle[0], "ptr", $lpData[0], "ulong", 0, "dword", 0x8000)
    Else
        $err = 4
    EndIf
    DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $procHandle[0])
    If $err Then
        Return SetError($err, 0, -1)
    Else
        Return $return
    EndIf
EndFunc   ;==>_SysTrayGetButtonInfo

;===============================================================================
;
; Function Name:    _SysTrayIconHandle($iIndex, $iWin = 1)
; Description:      Gets hwnd of window associated with systray icon of given index
; Parameter(s):     $iIndex     - icon index (Note: starting from 0)
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Requirement(s):
; Return Value(s):  On Success - Returns hwnd of found icon
;                   On Failure - Sets @error and returns -1
;                   | See _SysTrayGetButtonInfo for @error returns
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconHandle($iIndex, $iWin = 1)
    Local $TRAYDATA = _SysTrayGetButtonInfo($iIndex, $iWin, 2)
    If @error Then
        Return SetError(@error, 0, -1)
    Else
        Return Ptr(DllStructGetData($TRAYDATA, 1))
    EndIf
EndFunc   ;==>_SysTrayIconHandle

;===============================================================================
;
; Function Name:    _SysTrayIconTooltip($iIndex, $iWin = 1)
; Description:      Gets the tooltip text of systray icon of given index
; Parameter(s):     $iIndex     - icon index (Note: starting from 0)
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Requirement(s):
; Return Value(s):  On Success - Returns tooltip text of icon
;                   On Failure - Sets @error and returns -1
;                   | See _SysTrayGetButtonInfo for @error returns
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconTooltip($iIndex, $iWin = 1)
    Local $ret = _SysTrayGetButtonInfo($iIndex, $iWin, 3)
    If @error Then
        Return SetError(@error, 0, -1)
    Else
        Return $ret
    EndIf
EndFunc   ;==>_SysTrayIconTooltip

;===============================================================================
;
; Function Name:    _SysTrayIconPos($iIndex, $iWin = 1)
; Description:      Gets x & y position of systray icon
; Parameter(s):     $iIndex     - icon index (Note: starting from 0)
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Requirement(s):
; Return Value(s):  On Success - Returns array, x [0] and y [1] position of icon
;                   On Failure - Sets @error and returns -1
;                   | -1       - Icon is hidden (Autohide on XP, etc)
;                   | See _SysTrayGetButtonInfo for additional @error returns
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconPos($iIndex, $iWin = 1)
    Local $ret = _SysTrayGetButtonInfo($iIndex, $iWin, 4)
    If @error Then
        Return SetError(@error, 0, -1)
    Else
        If $ret = -1 Then
            Return SetError(-1, 0, -1)
        Else
            Return $ret
        EndIf
    EndIf
EndFunc   ;==>_SysTrayIconPos

;===============================================================================
;
; Function Name:    _SysTrayIconVisible($iIndex, $iWin = 1)
; Description:      Gets the visibility of a systray icon
; Parameter(s):     $iIndex     - icon index (Note: starting from 0)
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Requirement(s):
; Return Value(s):  On Success - Returns True (visible) or False (hidden)
;                   On Failure - Sets @error and returns -1
;                   | See _SysTrayGetButtonInfo for @error returns
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconVisible($iIndex, $iWin = 1)
    Local $TBBUTTON = _SysTrayGetButtonInfo($iIndex, $iWin, 1)
    If @error Then
        Return SetError(@error, 0, -1)
    Else
        Return Not BitAND(DllStructGetData($TBBUTTON, 3), 8) ;TBSTATE_HIDDEN
    EndIf
EndFunc   ;==>_SysTrayIconVisible

;===============================================================================
;
; Function Name:    _SysTrayIconHide($index, $iFlag, $iWin = 1)
; Description:      Hides / unhides any icon on systray
;
; Parameter(s):     $index      - icon index. Can be queried with _SysTrayIconIndex()
;                   $iFlag      - hide (1) or show (0) icon
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Requirement(s):
; Return Value(s):  On Success - Returns 1 if operation was successfull or 0 if
;                   icon was already hidden/unhidden
;                   On Failure - Sets @error and returns -1
;                   | See _SysTrayGetButtonInfo for @error returns
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconHide($index, $iFlag, $iWin = 1)
;~     Local Const $TB_HIDEBUTTON = 0x0404 ; WM_USER + 4
    Local $TBBUTTON = _SysTrayGetButtonInfo($index, $iWin, 1)
    If @error Then Return SetError(@error, 0, -1)
    Local $visible = Not BitAND(DllStructGetData($TBBUTTON, 3), 8) ;TBSTATE_HIDDEN
    If ($iFlag And Not $visible) Or (Not $iFlag And $visible) Then
        Return 0
    Else
        Local $TRAYDATA = _SysTrayGetButtonInfo($index, $iWin, 2)
        If @error Then Return SetError(@error, 0, -1)
        Local $NOTIFYICONDATA = DllStructCreate("dword cbSize;hwnd hWnd;uint uID;uint uFlags;uint uCallbackMessage;handle hIcon;wchar szTip[128];" _
            & "dword dwState;dword dwStateMask;wchar szInfo[256];uint uVersion;wchar szInfoTitle[64];dword dwInfoFlags;" _
            & "STRUCT;ulong;ushort;ushort;byte[8];ENDSTRUCT;handle hBalloonIcon")
        DllStructSetData($NOTIFYICONDATA, 1, DllStructGetSize($NOTIFYICONDATA))
        DllStructSetData($NOTIFYICONDATA, 2, Ptr(DllStructGetData($TRAYDATA, 1)))
        DllStructSetData($NOTIFYICONDATA, 3, DllStructGetData($TRAYDATA, 2))
        DllStructSetData($NOTIFYICONDATA, 4, 8) ; NIF_STATE
        DllStructSetData($NOTIFYICONDATA, 8, $iFlag) ; dw_State, 0 or 1 = NIS_HIDDEN
        DllStructSetData($NOTIFYICONDATA, 9, 1) ; dwStateMask
        Local $ret = DllCall("shell32.dll", "bool", "Shell_NotifyIconW", "dword", 0x1, "struct*", $NOTIFYICONDATA) ; NIM_MODIFY
        DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", WinGetHandle("[CLASS:Shell_TrayWnd]"), "uint", 0x001A, "wparam", 0, "lparam", 0) ; WM_SETTINGCHANGE
        If IsArray($ret) And $ret[0] Then
            Return 1
        Else
            Return 0
        EndIf
;~      $ret = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $trayHwnd, "uint", $TB_HIDEBUTTON, "wparam", DllStructGetData($TBBUTTON, 2), "lparam", $iHide)
;~      If @error Or Not $ret[0] Then
;~          $return = -1
;~      Else
;~          $return = $ret[0]
;~      EndIf
    EndIf
EndFunc   ;==>_SysTrayIconHide

;===============================================================================
;
; Function Name:    _SysTrayIconMove($curPos, $newPos, $iWin = 1)
; Description:      Moves systray icon
;
; Parameter(s):     $curPos     - icon's current index (0 based)
;                   $newPos     - icon's new position
;                                 ($curPos+1 = one step to right, $curPos-1 = one step to left)
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Requirement(s):   AutoIt3 Beta
; Return Value(s):  On Success - Returns 1 if operation was successfull, 0 if not
;                   On Failure - Sets @error and returns -1
;                   | 1        - Bad parameters
;                   | 2        - Failed to find tray window
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconMove($curPos, $newPos, $iWin = 1)
    Local Const $TB_MOVEBUTTON = 0x0452 ; WM_USER + 82
    Local $iconCount = _SysTrayIconCount($iWin)
    If $curPos < 0 Or $newPos < 0 Or $curPos > $iconCount - 1 Or $newPos > $iconCount - 1 Or Not IsInt($curPos) Or Not IsInt($newPos) Then Return SetError(1, 0, -1)
    Local $hWnd = _FindTrayToolbarWindow($iWin)
    If $hWnd = -1 Then Return SetError(2, 0, -1)
    Local $ret = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $TB_MOVEBUTTON, "wparam", $curPos, "lparam", $newPos)
    If @error Or Not $ret[0] Then
        Return 0
    Else
        Return 1
    EndIf
EndFunc   ;==>_SysTrayIconMove

;===============================================================================
;
; Function Name:    _SysTrayIconRemove($index, $iWin = 1)
; Description:      Removes systray icon completely.
;
; Parameter(s):     $index      - Icon index (first icon is 0)
;                   $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Return Value(s):  On Success - Returns 1 if icon successfully removed, 0 if not
;                   On Failure - Sets @error and returns -1
;                   | See _SysTrayGetButtonInfo for @error returns
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _SysTrayIconRemove($index, $iWin = 1)
    Local Const $TB_DELETEBUTTON = 1046
    Local $TRAYDATA = _SysTrayGetButtonInfo($index, $iWin, 2)
    If @error Then Return SetError(@error, 0, -1)
    Local $NOTIFYICONDATA = DllStructCreate("dword cbSize;hwnd hWnd;uint uID;uint uFlags;uint uCallbackMessage;handle hIcon;wchar szTip[128];" _
        & "dword dwState;dword dwStateMask;wchar szInfo[256];uint uVersion;wchar szInfoTitle[64];dword dwInfoFlags;" _
        & "STRUCT;ulong;ushort;ushort;byte[8];ENDSTRUCT;handle hBalloonIcon")
    DllStructSetData($NOTIFYICONDATA, 1, DllStructGetSize($NOTIFYICONDATA))
    DllStructSetData($NOTIFYICONDATA, 2, Ptr(DllStructGetData($TRAYDATA, 1)))
    DllStructSetData($NOTIFYICONDATA, 3, DllStructGetData($TRAYDATA, 2))
    Local $ret = DllCall("shell32.dll", "bool", "Shell_NotifyIconW", "dword", 0x2, "struct*", $NOTIFYICONDATA) ; NIM_DELETE
    DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", WinGetHandle("[CLASS:Shell_TrayWnd]"), "uint", 0x001A, "wparam", 0, "lparam", 0) ; WM_SETTINGCHANGE
    If IsArray($ret) And $ret[0] Then
        Return 1
    Else
        Return 0
    EndIf
;~  Local $hWnd = _FindTrayToolbarWindow($iWin)
;~  If $hwnd = -1 Then Return -1
;~  Local $ret = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $TB_DELETEBUTTON, "wparam", $index, "lparam", 0)
;~  If @error Or Not $ret[0] Then Return -1
;~  Return $ret[0]
EndFunc   ;==>_SysTrayIconRemove

;===============================================================================
;
; Function Name:    _FindTrayToolbarWindow($iWin = 1)
; Description:      Utility function for finding Toolbar window hwnd
; Parameter(s):     $iWin
;                   | 1         - ToolbarWindow32, Win2000+
;                   | 2         - NotifyIconOverflowWindow, Win7+
;
; Requirement(s):
; Return Value(s):  On Success - Returns Toolbar window hwnd
;                   On Failure - returns -1
;
; Author(s):        Tuape, Erik Pilsits
;
;===============================================================================
Func _FindTrayToolbarWindow($iWin = 1)
    Local $hwnd, $ret = -1
    If $iWin = 1 Then
        $hWnd = DllCall("user32.dll", "hwnd", "FindWindow", "str", "Shell_TrayWnd", "ptr", 0)
        If @error Then Return -1
        $hWnd = DllCall("user32.dll", "hwnd", "FindWindowEx", "hwnd", $hWnd[0], "hwnd", 0, "str", "TrayNotifyWnd", "ptr", 0)
        If @error Then Return -1
        If @OSVersion <> "WIN_2000" Then
            $hWnd = DllCall("user32.dll", "hwnd", "FindWindowEx", "hwnd", $hWnd[0], "hwnd", 0, "str", "SysPager", "ptr", 0)
            If @error Then Return -1
        EndIf
        $hWnd = DllCall("user32.dll", "hwnd", "FindWindowEx", "hwnd", $hWnd[0], "hwnd", 0, "str", "ToolbarWindow32", "ptr", 0)
        If @error Then Return -1
        $ret = $hwnd[0]
    ElseIf $iWin = 2 Then
        ; NotifyIconOverflowWindow for Windows 7
        $hWnd = DllCall("user32.dll", "hwnd", "FindWindow", "str", "NotifyIconOverflowWindow", "ptr", 0)
        If @error Then Return -1
        $hWnd = DllCall("user32.dll", "hwnd", "FindWindowEx", "hwnd", $hWnd[0], "hwnd", 0, "str", "ToolbarWindow32", "ptr", 0)
        If @error Then Return -1
        $ret = $hwnd[0]
    EndIf
    Return $ret
EndFunc   ;==>_FindTrayToolbarWindow

 
 
Example

#NoTrayIcon
#include <_SysTray.au3>
#include <Process.au3>

$count = _SysTrayIconCount()
ConsoleWrite("Count visible tray:  " & $count & @CRLF)
For $i = $count - 1 To 0 Step -1
    $handle = _SysTrayIconHandle($i)
    $visible = _SysTrayIconVisible($i)
    $pid = WinGetProcess($handle)
    $name = _ProcessGetName($pid)
    $title = WinGetTitle($handle)
    $tooltip = _SysTrayIconTooltip($i)
    ConsoleWrite("index:  " & $i & @TAB & "visible:  " & $visible & @TAB & "handle:  " & $handle & @TAB & "pid:  " & _
                    $pid & @TAB & "proc:  " & $name & @TAB & @TAB & "title:  " & $title & @TAB & @TAB & "tooltip:  " & $tooltip & @CRLF)
    If $pid = -1 Then _SysTrayIconRemove($i)
Next

If _FindTrayToolbarWindow(2) <> -1 Then
    ConsoleWrite("-====================-" & @CRLF)
    $countwin7 = _SysTrayIconCount(2)
    ConsoleWrite("Count overflow area:  " & $countwin7 & @CRLF)
    For $i = $countwin7 - 1 To 0 Step -1
        $handle = _SysTrayIconHandle($i, 2)
        $visible = _SysTrayIconVisible($i, 2)
        $pid = WinGetProcess($handle)
        $name = _ProcessGetName($pid)
        $title = WinGetTitle($handle)
        $tooltip = _SysTrayIconTooltip($i, 2)
        ConsoleWrite("index:  " & $i & @TAB & "visible:  " & $visible & @TAB & "handle:  " & $handle & @TAB & "pid:  " & _
                        $pid & @TAB & "proc:  " & $name & @TAB & @TAB & "title:  " & $title & @TAB & @TAB & "tooltip:  " & $tooltip & @CRLF)
        If $pid = -1 Then _SysTrayIconRemove($i, 2)
    Next
EndIf
Edited by wraithdu
2 people like this

Share this post


Link to post
Share on other sites



Posted

wraithdu,

Works fine on Vista with taskbar showing and auto-hidden.

In return, could I ask you a follow-on question?

Do you know of any way to display an auto-hidden taskbar so that the icons are available for clicking, other than by this rather crude method?

Send("{CTRLDOWN}") ; send <ctrl>-<esc> to bring up the Taskbar if hidden
Send("{ESC}")
Send("{CTRLUP}")
Send("{ESC}") ; get rid of the Start Menu to avoid confusion

It came up in a recent topic and I could not find a "programmatic" way of doing it.

M23

Share this post


Link to post
Share on other sites

Posted

Hmm, no. You could move the mouse to the bottom of the screen momentarily, or maybe ControlSend() a click to the taskbar window?

Share this post


Link to post
Share on other sites

Posted

This should work on Win2000+, but some testers on XP and Vista would be appreciated.

Example works on XP; haven't tested other functions yet.

Share this post


Link to post
Share on other sites

Posted

Hi, I used your script in Windows 7 x64 Professional, and it clears all the visible system tray icons instead of the dead ones. Do you know what might be happening? I'm new to AutoIt, so maybe I did something wrong with your code? I saved the first one as _SysTray.au3 and the second set of code as Example.au3 and ran Example.au3.

Share this post


Link to post
Share on other sites

Posted (edited)

This is not tested or coded for X64. It reads directly from explorer.exe's memory which is going to be different on X64. No big surprise it didn't work correctly.

Edited by wraithdu

Share this post


Link to post
Share on other sites

Posted

Ok, I've updated the UDF for possible X64 compatibility. Someone's gonna have to test that for me though.

Share this post


Link to post
Share on other sites

Posted

A quick update : I just ran the example script in the post and it deleted ALL the notification area icons!

I have 9 icons in the area, all of which are visible and the example script gives me this output:

Count visible tray:  9
index:  8   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
index:  7   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
index:  6   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
index:  5   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
index:  4   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
index:  3   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
index:  2   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
index:  1   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
index:  0   visible:  -3    handle:  -3 pid:  -1    proc:       title:  0       tooltip:  -3
>Exit code: 0    Time: 0.312

This means that _SysTrayIconHandle fails, and I think that _SysTrayGetButtonInfo is failing.

Right away, off the top of my head, I think that ReadProcessMemory etc is failing as I don't have Admin privileges/debug rights.

Any clues?

Share this post


Link to post
Share on other sites

Posted

A quick update : I just ran the example script in the post and it deleted ALL the notification area icons!

Same happened here :), though I have admin rights.

Share this post


Link to post
Share on other sites

Posted

Same happened here :), though I have admin rights.

Hmmm.. thanks for the feedback.

Can you confirm if you have the SeDebugPrivilige ?

I believe this is required for the functions to succeed.

Can the author(s) of this script please have a look into this?

Share this post


Link to post
Share on other sites

Posted

Can you confirm if you have the SeDebugPrivilige ?

Confirmed, all tray-icons deleted, still happens with the example below.

#NoTrayIcon
#include <_SysTray.au3>
#include <Process.au3>
#include <WinAPI.au3>

_GetPrivilege_SEDEBUG()

$count = _SysTrayIconCount()
ConsoleWrite("Count visible tray:  " & $count & @CRLF)
For $i = $count - 1 To 0 Step -1
    $handle = _SysTrayIconHandle($i)
    $visible = _SysTrayIconVisible($i)
    $pid = WinGetProcess($handle)
    $name = _ProcessGetName($pid)
    $title = WinGetTitle($handle)
    $tooltip = _SysTrayIconTooltip($i)
    ConsoleWrite("index:  " & $i & @TAB & "visible:  " & $visible & @TAB & "handle:  " & $handle & @TAB & "pid:  " & _
                    $pid & @TAB & "proc:  " & $name & @TAB & @TAB & "title:  " & $title & @TAB & @TAB & "tooltip:  " & $tooltip & @CRLF)
    If $pid = -1 Then _SysTrayIconRemove($i)
Next

If @OSVersion = "WIN_7" Then
    ConsoleWrite("-====================-" & @CRLF)
    $countwin7 = _SysTrayIconCount(2)
    ConsoleWrite("Count Win7 overflow area:  " & $countwin7 & @CRLF)
    For $i = $countwin7 - 1 To 0 Step -1
        $handle = _SysTrayIconHandle($i, 2)
        $visible = _SysTrayIconVisible($i, 2)
        $pid = WinGetProcess($handle)
        $name = _ProcessGetName($pid)
        $title = WinGetTitle($handle)
        $tooltip = _SysTrayIconTooltip($i, 2)
        ConsoleWrite("index:  " & $i & @TAB & "visible:  " & $visible & @TAB & "handle:  " & $handle & @TAB & "pid:  " & _
                        $pid & @TAB & "proc:  " & $name & @TAB & @TAB & "title:  " & $title & @TAB & @TAB & "tooltip:  " & $tooltip & @CRLF)
        If $pid = -1 Then _SysTrayIconRemove($i, 2)
    Next
EndIf



; By wraithdu
; http://www.autoitscript.com/forum/index.php?showtopic=88214&view=findpost&p=634408
; ####################### Below Func is Part of example - Needed to get commandline from more processes. ############
; ####################### Thanks for this function, wraithdu! (Didn't know it was your.) smile.gif #########################
Func _GetPrivilege_SEDEBUG()
    Local $tagLUIDANDATTRIB = "int64 Luid;dword Attributes"
    Local $count = 1
    Local $tagTOKENPRIVILEGES = "dword PrivilegeCount;byte LUIDandATTRIB[" & $count * 12 & "]" ; count of LUID structs * sizeof LUID struct
    Local $TOKEN_ADJUST_PRIVILEGES = 0x20
    Local $call = DllCall("advapi32.dll", "int", "OpenProcessToken", "ptr", _WinAPI_GetCurrentProcess(), "dword", $TOKEN_ADJUST_PRIVILEGES, "ptr*", "")
    Local $hToken = $call[3]
    $call = DllCall("advapi32.dll", "int", "LookupPrivilegeValue", "str", Chr(0), "str", "SeDebugPrivilege", "int64*", "")
    ;msgbox(262144,"",$call[3] & " " & _WinAPI_GetLastErrorMessage())
    Local $iLuid = $call[3]
    Local $TP = DllStructCreate($tagTOKENPRIVILEGES)
    Local $LUID = DllStructCreate($tagLUIDANDATTRIB, DllStructGetPtr($TP, "LUIDandATTRIB"))
    DllStructSetData($TP, "PrivilegeCount", $count)
    DllStructSetData($LUID, "Luid", $iLuid)
    DllStructSetData($LUID, "Attributes", $SE_PRIVILEGE_ENABLED)
    $call = DllCall("advapi32.dll", "int", "AdjustTokenPrivileges", "ptr", $hToken, "int", 0, "ptr", DllStructGetPtr($TP), "dword", 0, "ptr", Chr(0), "ptr", Chr(0))
    Return ($call[0] <> 0) ; $call[0] <> 0 is success
EndFunc   ;==>_GetPrivilege_SEDEBUG

Share this post


Link to post
Share on other sites

Posted

KaFu, It now works with a little patch:

http://www.autoitscript.com/forum/index.php?showtopic=105650&view=findpost&p=746750

:)

Share this post


Link to post
Share on other sites

Posted (edited)

What version of AutoIt are you using? I guess 'dword_ptr' was introduced in a beta somewhere that you don't have. Good catch Authenticity. I'll change the UDF for safety.

Edited by wraithdu

Share this post


Link to post
Share on other sites

Posted

Ok, I've updated the UDF for possible X64 compatibility. Someone's gonna have to test that for me though.

Thanks for taking the time to update this UDF wraithd, it's extremely useful. I'm running Win7 x64 and some of the functions are't working for me.

_SysTrayIconCount() works OK and returns the correct number of tray icons but when I try to get down to the interesting stuff, nothing works. For example, _SysTrayIconProcesses() returns an array of blank elements and _SysTrayIconTitles() returns 3 zeroes.

Share this post


Link to post
Share on other sites

Posted (edited)

I'm not sure what to tell you. What version of AutoIt are you using?

I just tested on my Win7 Pro x64 system with beta 3.3.1.5 and both of those functions work correctly. I tried running from Scite (runs as an x64 process), and compiled as both 32-bit and 64-bit. All 3 return the correct information, both titles and process names. Very simple script to test:

#include <_SysTray.au3>
#include <Array.au3>

$a = _SysTrayIconTitles()
_ArrayDisplay($a)
$a = _SysTrayIconProcesses()
_ArrayDisplay($a)
Edited by wraithdu

Share this post


Link to post
Share on other sites

Posted

Resolved the problem - I had to copy the UDF from a cached copy of the page yesterday as I was unable to reach autoitscript.com, now that I've re-copied it from the proper page, it's working correctly.

Share this post


Link to post
Share on other sites

Posted (edited)

One more question - the reason for using this was to retrieve the tooltip text from the network icon but instead of getting "Network - Internet Access", I'm getting "Network System Icon".

When I hover the mouse over the tray icon, I see "Network - Internet Access" - is there any way to retrieve this text?

Edited by idbirch

Share this post


Link to post
Share on other sites

Posted

You're probably just using the wrong function. See the example I posted. It shows how to get both the icon title and the tooltip.

Share this post


Link to post
Share on other sites

Posted (edited)

No, I'm definitely using the right function. Here's the console output for the Win7 x64 network tray icon using your example script:

index: 2 visible: True handle: 0x00000000000101B4 pid: 1796 proc: explorer.exe title: Network Flyout tooltip: Network System Icon

I have no idea where it's getting that Tooltip text from as that's not what appears when I hover over it.

EDIT: Ugh, turns out the Win7 network icon is a bit temperamental at best, the icon's status was no longer updating in my systray when the connection status changed. I rebooted and now the tips are being read correctly.

Edited by idbirch

Share this post


Link to post
Share on other sites

Posted

Do you know of any way to display an auto-hidden taskbar so that the icons are available for clicking, other than by this rather crude method?

Send("{CTRLDOWN}") ; send <ctrl>-<esc> to bring up the Taskbar if hidden
Send("{ESC}")
Send("{CTRLUP}")
Send("{ESC}") ; get rid of the Start Menu to avoid confusion

It came up in a recent topic and I could not find a "programmatic" way of doing it.

M23

; locates and right clicks the Icon for this script

#include <GuiToolbar.au3>
#include <_SysTray.au3>

$ToolTipString = 'Autoit - '&@ScriptName

$count = _SysTrayIconCount()
For $i = 0 to $count - 1
    $tooltip = _SysTrayIconTooltip($i)
    ConsoleWrite("index:  " & $i & @TAB & "tooltip:  " & $tooltip & @CRLF)
    If $tooltip = $ToolTipString then $Index = $i
Next

$hWnd = ControlGetHandle('[Class:Shell_TrayWnd]', '', '[Class:ToolbarWindow32;Instance:1]')
$iCommandID = _GUICtrlToolbar_IndexToCommand($hWnd, $Index)
$aRect = _GUICtrlToolbar_GetButtonRect ($hWnd, $iCommandID)
ControlClick($hWnd, '', '','Secondary',1,$aRect[0],$aRect[1])

Example code to locate and right click a notification(systray) icon even if the taskbar is hidden.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0

  • Recently Browsing   0 members

    No registered users viewing this page.