;www.autoitscript.com/forum/topic/134538-get-systray-icons-solved #NoTrayIcon #RequireAdmin #include #include #include #include #include #include #include #include #include #include #include #include Opt('SendKeyDelay', 0) Opt('MouseClickDelay', 0) Opt('SendKeyDownDelay', 0) Opt('MouseClickDownDelay', 0) Opt('MouseClickDragDelay', 0) Opt('WinTitleMatchMode', 3) Opt('WinWaitDelay', 0) $SystrayIconsInfo = _GetAllSystrayIconsInfo() If IsArray($SystrayIconsInfo) Then _ArrayDisplay($SystrayIconsInfo) _RemoveSystrayIcon('process', 0, '', 'explorer.exe', 1225) _RegisterWinEventHook($EVENT_OBJECT_CREATE, $EVENT_OBJECT_LOCATIONCHANGE) If @error Then MsgBox($MB_OK, 'Info', 'Failed to register event hook.') Exit EndIf While 1 Sleep(1000) WEnd Func _RegisterWinEventHook($sEventMin, $sEventMax, $sProcessPid = 0, $sCallbackFunc = '_WinEventProc') $sWinEventProc = DllCallbackRegister($sCallbackFunc, 'none', 'ptr;dword;hwnd;long;long;dword;dword') $sWinEventHook = _WinAPI_SetWinEventHook($sEventMin, $sEventMax, DllCallbackGetPtr($sWinEventProc), $sProcessPid) Switch $sWinEventHook Case 0 Return SetError(1, 0, 0) Case Else Return SetExtended($sWinEventProc, $sWinEventHook) EndSwitch EndFunc Func _WinEventProc($hEventHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iThreadId, $iEventTime) If not IsDeclared('__SystrayIconsCountList') Then Global $__SystrayIconsCountList[3][2] = [['Shell_TrayWnd', 'NotifyIconOverflowWindow'], [0, 0], [False, False]] Switch $iEvent Case $EVENT_OBJECT_CREATE, $EVENT_OBJECT_LOCATIONCHANGE If ($iEvent = $EVENT_OBJECT_CREATE and $iObjectID = $OBJID_CLIENT) or ($iEvent = $EVENT_OBJECT_LOCATIONCHANGE and $iObjectID = $OBJID_WINDOW) Then If _WinAPI_GetClassName($hWnd) = 'ToolbarWindow32' Then $sParentWndClass = _WinAPI_GetClassName(_WinAPI_GetAncestor($hWnd, $GA_ROOT)) Switch $sParentWndClass Case 'Shell_TrayWnd', 'NotifyIconOverflowWindow' $sParentWndIndex = 0 If $sParentWndClass = 'NotifyIconOverflowWindow' Then $sParentWndIndex = 1 $sSystrayIconsCount = _GUICtrlToolbar_ButtonCount($hWnd) If $sSystrayIconsCount < $__SystrayIconsCountList[1][$sParentWndIndex] Then $__SystrayIconsCountList[1][$sParentWndIndex] = 0 If $sSystrayIconsCount <> $__SystrayIconsCountList[1][$sParentWndIndex] Then $__SystrayIconsCountList[1][$sParentWndIndex] = $sSystrayIconsCount $__SystrayIconsCountList[2][$sParentWndIndex] = False Else If $iEvent = $EVENT_OBJECT_LOCATIONCHANGE and $__SystrayIconsCountList[1][$sParentWndIndex] > 0 and $__SystrayIconsCountList[2][$sParentWndIndex] = False Then $__SystrayIconsCountList[2][$sParentWndIndex] = True _RemoveSystrayIcon('process', 0, '', 'explorer.exe', 1225) EndIf EndIf EndSwitch EndIf EndIf EndSwitch EndFunc Func _GetAllSystrayIconsInfo($sSystrayWndHandle = 0) $sSystrayIconsTrayDataDllStructList = _GetSystrayIconsTrayDataDllStructList($sSystrayWndHandle) If @error Then Return SetError(1, @error, '') Local $sSystrayIconsInfoList[UBound($sSystrayIconsTrayDataDllStructList)][3] = [['Icon Text', 'Process Name', 'Icon Uid']] For $i = 1 to UBound($sSystrayIconsTrayDataDllStructList) - 1 $tTrayData = $sSystrayIconsTrayDataDllStructList[$i][2] $sSystrayIconsInfoList[$i][0] = _GUICtrlToolbar_GetButtonText($sSystrayIconsTrayDataDllStructList[$i][0], $sSystrayIconsTrayDataDllStructList[$i][1]) $sSystrayIconsInfoList[$i][1] = _ProcessGetName(WinGetProcess(DllStructGetData($tTrayData, 'hWnd'))) $sSystrayIconsInfoList[$i][2] = DllStructGetData($tTrayData, 'uID') Next Return $sSystrayIconsInfoList EndFunc Func _RemoveSystrayIcon($sMode, $sSystrayWndHandle = 0, $sSystrayIconTitle = '', $sProcessName = '', $sSystrayIconUid = 0) ;$sSystrayIconTitle contains list of full or partial icon titles (with | as delimiter) related to wanted systray icon ;$sMode values: title or process If $sMode <> 'title' and $sMode <> 'process' Then Return SetError(1, 0, False) If $sProcessName = 'explorer.exe' and not WinExists('[CLASS:PNIHiddenWnd]') Then Return SetError(2, 0, False) $sSystrayIconTrayDataInfoList = _GetSystrayIconTrayDataInfo($sMode, $sSystrayWndHandle, $sSystrayIconTitle, $sProcessName, $sSystrayIconUid) If @error Then Return SetError(3, @error, False) $tTrayData = $sSystrayIconTrayDataInfoList[2] If $sProcessName = 'explorer.exe' Then $sFuncReturn = _GUICtrlToolbar_DeleteButton($sSystrayIconTrayDataInfoList[0], $sSystrayIconTrayDataInfoList[1]) Else $tNotifyIconData = DllStructCreate($tagNOTIFYICONDATA) DllStructSetData($tNotifyIconData, 'Size', DllStructGetSize($tNotifyIconData)) DllStructSetData($tNotifyIconData, 'hWnd', DllStructGetData($tTrayData, 'hWnd')) DllStructSetData($tNotifyIconData, 'ID', DllStructGetData($tTrayData, 'uID')) $sFuncReturn = _WinAPI_ShellNotifyIcon($NIM_DELETE, $tNotifyIconData) EndIf If $sFuncReturn = False Then Return SetError(4, 0, False) If $sProcessName = 'explorer.exe' Then If @TrayIconVisible = 1 Then TraySetState($TRAY_ICONSTATE_HIDE) TraySetState($TRAY_ICONSTATE_SHOW) Else TraySetState($TRAY_ICONSTATE_SHOW) TraySetState($TRAY_ICONSTATE_HIDE) EndIf EndIf Return True EndFunc Func _GetSystrayIconTrayDataInfo($sMode, $sSystrayWndHandle = 0, $sSystrayIconTitle = '', $sProcessName = '', $sSystrayIconUid = 0) ;$sSystrayIconTitle contains list of full or partial icon titles (with | as delimiter) related to wanted systray icon ;$sMode values: title or process Local $sSystrayIconTrayDataInfoList[3] If $sMode <> 'title' and $sMode <> 'process' Then Return SetError(1, 0, '') $sSystrayIconsTrayDataDllStructList = _GetSystrayIconsTrayDataDllStructList($sSystrayWndHandle) If @error Then Return SetError(2, @error, '') $sMatchFound = False For $i = 1 to UBound($sSystrayIconsTrayDataDllStructList) - 1 $tTrayData = $sSystrayIconsTrayDataDllStructList[$i][2] Switch $sMode Case 'title' $sSystrayIconTitleList = StringSplit($sSystrayIconTitle, '|', $STR_ENTIRESPLIT) $sSystrayIconText = _GUICtrlToolbar_GetButtonText($sSystrayIconsTrayDataDllStructList[$i][0], $sSystrayIconsTrayDataDllStructList[$i][1]) For $j = 1 to $sSystrayIconTitleList[0] If StringInStr($sSystrayIconText, $sSystrayIconTitleList[$j]) Then $sMatchFound = True ExitLoop EndIf Next Case 'process' If _ProcessGetName(WinGetProcess(DllStructGetData($tTrayData, 'hWnd'))) = $sProcessName and DllStructGetData($tTrayData, 'uID') = $sSystrayIconUid Then $sMatchFound = True EndSwitch If $sMatchFound = True Then $sSystrayIconTrayDataInfoList[0] = $sSystrayIconsTrayDataDllStructList[$i][0] $sSystrayIconTrayDataInfoList[1] = $sSystrayIconsTrayDataDllStructList[$i][1] $sSystrayIconTrayDataInfoList[2] = $tTrayData ExitLoop EndIf Next If $sMatchFound = False Then Return SetError(3, 0, '') Return $sSystrayIconTrayDataInfoList EndFunc Func _GetSystrayIconsTrayDataDllStructList($sSystrayWndHandle = 0) Local $sReadBytes Local $sSystrayIconsTrayDataDllStructList[1][3] = [['Systray toolbar handle', 'Icon command identifier', 'TrayData DllStruct']] If @OSBuild < 7600 or IsHWnd($sSystrayWndHandle) or RegRead('HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer', 'EnableAutoTray') = '0' Then $sSystrayWndCount = 1 Else $sSystrayWndCount = 2 EndIf $sProcessHandle = _WinAPI_OpenProcess(BitOR($PROCESS_VM_OPERATION, $PROCESS_VM_READ), False, WinGetProcess(WinGetHandle('[CLASS:Shell_TrayWnd]')), True) If $sProcessHandle = 0 Then Return SetError(1, 0, '') $sAllSystrayIconsCount = 0 For $i = 1 to $sSystrayWndCount If IsHWnd($sSystrayWndHandle) Then $sSystrayToolbarHandle = _GetSystrayToolbarHandle($sSystrayWndHandle) Else Switch $i Case 1 $sSystrayToolbarHandle = _GetSystrayToolbarHandle(WinGetHandle('[CLASS:Shell_TrayWnd]')) Case 2 $sSystrayToolbarHandle = _GetSystrayToolbarHandle(WinGetHandle('[CLASS:NotifyIconOverflowWindow]')) EndSwitch EndIf If IsHWnd($sSystrayToolbarHandle) Then $sSystrayIconsCount = _GUICtrlToolbar_ButtonCount($sSystrayToolbarHandle) If $sSystrayIconsCount > 0 Then ReDim $sSystrayIconsTrayDataDllStructList[UBound($sSystrayIconsTrayDataDllStructList) + $sSystrayIconsCount][3] For $j = 0 to $sSystrayIconsCount - 1 $sSystrayIconCommandId = _GUICtrlToolbar_IndexToCommand($sSystrayToolbarHandle, $j) $sSystrayIconParam = _GUICtrlToolbar_GetButtonParam($sSystrayToolbarHandle, $sSystrayIconCommandId) $tTrayData = DllStructCreate('hwnd hWnd;uint uID;uint uCallbackMessage;dword Reserved[2];ptr hIcon') _WinAPI_ReadProcessMemory($sProcessHandle, $sSystrayIconParam, DllStructGetPtr($tTrayData), DllStructGetSize($tTrayData), $sReadBytes) $sAllSystrayIconsCount +=1 $sSystrayIconsTrayDataDllStructList[$sAllSystrayIconsCount][0] = $sSystrayToolbarHandle $sSystrayIconsTrayDataDllStructList[$sAllSystrayIconsCount][1] = $sSystrayIconCommandId $sSystrayIconsTrayDataDllStructList[$sAllSystrayIconsCount][2] = $tTrayData Next EndIf EndIf Next _WinAPI_CloseHandle($sProcessHandle) ReDim $sSystrayIconsTrayDataDllStructList[$sAllSystrayIconsCount + 1][3] If UBound($sSystrayIconsTrayDataDllStructList) - 1 = 0 Then Return SetError(2, 0, '') Return $sSystrayIconsTrayDataDllStructList EndFunc Func _GetSystrayToolbarHandle($sSystrayWndHandle) Switch _WinAPI_GetClassName($sSystrayWndHandle) Case 'Shell_TrayWnd' If @OSBuild < 10240 Then Return ControlGetHandle($sSystrayWndHandle, '', '[CLASS:ToolbarWindow32; INSTANCE:1]') Else Return ControlGetHandle($sSystrayWndHandle, '', '[CLASS:ToolbarWindow32; INSTANCE:3]') EndIf Case 'NotifyIconOverflowWindow' Return ControlGetHandle($sSystrayWndHandle, '', '[CLASS:ToolbarWindow32; INSTANCE:1]') Case Else Return SetError(1, 0, 0) EndSwitch EndFunc