Skip to content

Instantly share code, notes, and snippets.

@mortalis13
Last active June 14, 2024 11:05
Show Gist options
  • Save mortalis13/837ccf0ccd43d25ffbcb43af5ebb2f80 to your computer and use it in GitHub Desktop.
Save mortalis13/837ccf0ccd43d25ffbcb43af5ebb2f80 to your computer and use it in GitHub Desktop.

Script tested on Windows 10, with all icons visible setting.
Removes an icon by process name from the system tray.

; AutoHotkey v2
; Based on https://www.autohotkey.com/boards/viewtopic.php?p=414590#p414590 "[LIB] TrayIcon - Sean's TrayIcon for Unicode and 64 bit"

TrayIcon_GetTrayBar(sTray := "Shell_TrayWnd") {
  idxTB := "", nTB := ""
  dhw := A_DetectHiddenWindows
  DetectHiddenWindows(1)
  for k in WinGetControls("ahk_class " sTray)
    if RegExMatch(k, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", &nTB)
      loop nTB[] {
        hWnd    := ControlGetHwnd("ToolbarWindow32" A_Index, "ahk_class " sTray)
        hParent := DllCall("GetParent", "Ptr",hWnd)
        sClass  := WinGetClass("ahk_id " hParent)
        if not (sClass == "SysPager" or sClass == "NotifyIconOverflowWindow")
          continue
        idxTB := A_Index
        break
      }
  DetectHiddenWindows(dhw)
  return idxTB
}

; sExeName - exe name or empty for all icons
; oTrayInfo - array of objects icons data:
;   idx     - 0 based tray icon index
;   idcmd   - Command identifier associated with the button
;   pid     - Process ID
;   uid     - Application defined identifier for the icon
;   msgid   - Application defined callback message
;   hicon   - Handle to the tray icon
;   hwnd    - Window handle
;   class   - Window class
;   process - Process executable
;   tray    - Tray Type (Shell_TrayWnd or NotifyIconOverflowWindow)
;   tooltip - Tray icon tooltip
TrayIcon_GetInfo(sExeName := "") {
  dhw := A_DetectHiddenWindows
  DetectHiddenWindows(1)

  oTrayInfo    := []
  for sTray in ["Shell_TrayWnd", "NotifyIconOverflowWindow"] {
    idxTB      := TrayIcon_GetTrayBar(sTray)
    pidTaskbar := WinGetPID("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)

    btn        := Buffer(A_Is64bitOS ? 32 : 20, 0)
    nfo        := Buffer(A_Is64bitOS ? 32 : 24, 0)
    tip        := Buffer(128 * 2, 0)

    res := SendMessage(TB_BUTTONCOUNT := 0x0418, 0, 0, "ToolbarWindow32" idxTB, "ahk_class " sTray)
    Loop res {
      SendMessage(TB_GETBUTTON := 0x0417, A_Index - 1, pRB, "ToolbarWindow32" idxTB, "ahk_class " sTray)

      DllCall("ReadProcessMemory", "Ptr",hProc, "Ptr",pRB, "Ptr",btn.Ptr, "UPtr",btn.Size, "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.Ptr, "UPtr",nfo.Size, "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")

      nPid     := WinGetPID("ahk_id " hWnd)
      sProcess := WinGetProcessName("ahk_id " hWnd)
      sClass   := WinGetClass("ahk_id " hWnd)

      If ( (sExeName = "-" && !sProcess) || (sExeName == "--" && !nPid) || (!sExeName) || (sExeName = sProcess) || (sExeName == nPid))
      {
        DllCall("ReadProcessMemory"   , "Ptr",hProc, "Ptr",iString, "Ptr",tip.Ptr, "UPtr",tip.Size, "UPtr",0)
        oTrayInfo.Push(Map( "idx"     , A_Index - 1
                          , "idcmd"   , idCmd
                          , "pid"     , nPid
                          , "uid"     , uId
                          , "msgid"   , msgId
                          , "hicon"   , hIcon
                          , "hwnd"    , hWnd
                          , "class"   , sClass
                          , "process" , sProcess
                          , "tooltip" , StrGet(tip.Ptr, "UTF-16")
                          , "tray"    , sTray))
      }
    }
    DllCall("VirtualFreeEx", "Ptr",hProc, "Ptr",pRB, "UPtr",0, "UInt",0x8000)
    DllCall("CloseHandle",   "Ptr",hProc)
  }
  DetectHiddenWindows(dhw)
  return oTrayInfo
}

TrayIcon_Delete(idx, sTray := "Shell_TrayWnd") {
    dhw := A_DetectHiddenWindows
    DetectHiddenWindows(1)
    idxTB := TrayIcon_GetTrayBar()
    SendMessage(TB_DELETEBUTTON := 0x0416, idx, 0, "ToolbarWindow32" idxTB, "ahk_class " sTray)
    SendMessage(0x001A, 0, 0,, "ahk_class " sTray)
    DetectHiddenWindows(dhw)
}


icons := TrayIcon_GetInfo("")
info := ""
for item in icons
    info .= item["idx"] ": " item["process"] "`n"
MsgBox info


icons := TrayIcon_GetInfo("someapp.exe")
If icons.Length = 1
    TrayIcon_Delete(icons[1]["idx"])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment