Home | Blog | Software | Reviews and Features | Forum | Help | Donate | About us
topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • December 10, 2016, 02:53:11 AM
  • Proudly celebrating 10 years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: AHK_L tray code to clear orphaned icons that actually seems to work  (Read 1668 times)

MilesAhead

  • Supporting Member
  • Joined in 2009
  • **
  • Posts: 7,290
    • View Profile
    • Miles Ahead Software
    • Donate to Member
This is not my code. The author has generously granted permission to distribute the utility with your programs. If your app is written in AHK_L then you could just include the function. For apps implemented in other languages, compile as a stand-alone exe and run the exe when you wish to clear the task tray of dead icons.

As one example, I wrote a hack for my own use that launches Giganews accelerator, then runs my Newsreader and waits.  When I close the Newsreader app, it kills Giganews, then runs the orphan killer app to clear the GA icon from the tray.

NoTrayOrphans

cranioscopical

  • Friend of the Site
  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 4,368
    • View Profile
    • Donate to Member
Re: AHK_L tray code to clear orphaned icons that actually seems to work
« Reply #1 on: October 06, 2012, 01:32:44 PM »
Thanks, MilesAhead.
I had some code to do this under XP but it broke with W7. As a stop-gap measure I've been running the mouse around under program control in order to clean up  :-[

MilesAhead

  • Supporting Member
  • Joined in 2009
  • **
  • Posts: 7,290
    • View Profile
    • Miles Ahead Software
    • Donate to Member
Re: AHK_L tray code to clear orphaned icons that actually seems to work
« Reply #2 on: October 06, 2012, 02:11:04 PM »
Thanks, MilesAhead.
I had some code to do this under XP but it broke with W7. As a stop-gap measure I've been running the mouse around under program control in order to clean up  :-[

This is the 3rd solution I've tried that I can remember.  The first 2 seemed to work about 1/2 the time. This one looks more promising.

cranioscopical

  • Friend of the Site
  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 4,368
    • View Profile
    • Donate to Member
Re: AHK_L tray code to clear orphaned icons that actually seems to work
« Reply #3 on: October 06, 2012, 03:34:25 PM »
Didn't work for me on a first, quick try.  :(
I'll take another look later…

MilesAhead

  • Supporting Member
  • Joined in 2009
  • **
  • Posts: 7,290
    • View Profile
    • Miles Ahead Software
    • Donate to Member
Re: AHK_L tray code to clear orphaned icons that actually seems to work
« Reply #4 on: October 06, 2012, 04:08:33 PM »
Didn't work for me on a first, quick try.  :(
I'll take another look later…

You have to compile from the source.  The attachment posted by the author with no compression or icon didn't work for me at all.

I made a small mod for calling it as a function that sets DetectHiddenWindows On, then restores the original state at the end of the function. For AHK_L apps you can just include the file and call the function.

;~ #NoTrayIcon
;~ #SingleInstance force

;~ NoTrayOrphans()
;~ ExitApp
;~ Return

NoTrayOrphans() {
  DetectState := A_DetectHiddenWindows  ; mod MilesAhead
  DetectHiddenWindows, On  ; mod MilesAhead
   TrayInfo:= TrayIcons(sExeName,"ahk_class Shell_TrayWnd","ToolbarWindow32" . GetTrayBar()) "`n"
      . TrayIcons(sExeName,"ahk_class NotifyIconOverflowWindow","ToolbarWindow321")
   While Item:= StrX(TrayInfo, "idx:" ,N,0, "`n" ,1,0, N) {
      ProcessName:= StrX(Item, "| Process: ",1,11, "|",1,2)
      ProcesshWnd:= StrX(Item, "hWnd: ",1,6, " ",1,1)
      ProcessuID := StrX(Item, "| uID: ",1,7, " ",1,1)
      If !ProcessName
         RemoveTrayIcon(ProcesshWnd, ProcessuID)
      }
    DetectHiddenWindows, %DetectState%  ; mod MilesAhead
   }
RemoveTrayIcon(hWnd, uID, nMsg = 0, hIcon = 0, nRemove = 2) {
   NumPut(VarSetCapacity(ni,444,0), ni)
   NumPut(hWnd , ni, 4)
   NumPut(uID  , ni, 8)
   NumPut(1|2|4, ni,12)
   NumPut(nMsg , ni,16)
   NumPut(hIcon, ni,20)
   Return   DllCall("shell32\Shell_NotifyIconA", "Uint", nRemove, "Uint", &ni)
   }
TrayIcons(sExeName,traywindow,control) {
   DetectHiddenWindows, On
   WinGet,   pidTaskbar, PID, %traywindow%
   hProc:=   DllCall("OpenProcess", "Uint", 0x38, "int", 0, "Uint", pidTaskbar)
   pProc:=   DllCall("VirtualAllocEx", "Uint", hProc, "Uint", 0, "Uint", 32, "Uint", 0x1000, "Uint", 0x4)
   SendMessage, 0x418, 0, 0, %control%, %traywindow%
   Loop,   %ErrorLevel%
   {
   SendMessage, 0x417, A_Index-1, pProc, %control%, %traywindow%
   VarSetCapacity(btn,32,0), VarSetCapacity(nfo,32,0)
   DllCall("ReadProcessMemory", "Uint", hProc, "Uint", pProc, "Uint", &btn, "Uint", 32, "Uint", 0)
   iBitmap   := NumGet(btn, 0)
   idn   := NumGet(btn, 4)
   Statyle := NumGet(btn, 8)
   If   dwData   := NumGet(btn,12)
   iString   := NumGet(btn,16)
   Else   dwData   := NumGet(btn,16,"int64"), iString:=NumGet(btn,24,"int64")
   DllCall("ReadProcessMemory", "Uint", hProc, "Uint", dwData, "Uint", &nfo, "Uint", 32, "Uint", 0)
   If   NumGet(btn,12)
   hWnd   := NumGet(nfo, 0)
   ,   uID   := NumGet(nfo, 4)
   ,   nMsg   := NumGet(nfo, 8)
   ,   hIcon   := NumGet(nfo,20)
   Else   hWnd   := NumGet(nfo, 0,"int64"), uID:=NumGet(nfo, 8), nMsg:=NumGet(nfo,12), hIcon := NumGet(nfo,24)
   WinGet, pid, PID,              ahk_id %hWnd%
   WinGet, sProcess, ProcessName, ahk_id %hWnd%
   WinGetClass, sClass,           ahk_id %hWnd%
   If !sExeName || (sExeName = sProcess) || (sExeName = pid)
   VarSetCapacity(sTooltip,128), VarSetCapacity(wTooltip,128*2)
   ,   DllCall("ReadProcessMemory", "Uint", hProc, "Uint", iString, "Uint", &wTooltip, "Uint", 128*2, "Uint", 0)
   ,   DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", wTooltip, "int", -1, "str", sTooltip, "int", 128, "Uint", 0, "Uint", 0)
   ,   sTrayIcons .= "idx: " . A_Index-1 . " | idn: " . idn . " | Pid: " . pid . " | uID: " . uID . " | MessageID: " . nMsg . " | hWnd: " . hWnd . " | Class: " . sClass . " | Process: " . sProcess . " | Icon: " . hIcon . " | Tooltip: " . wTooltip . "`n"
   }
   DllCall("VirtualFreeEx", "Uint", hProc, "Uint", pProc, "Uint", 0, "Uint", 0x8000)
   DllCall("CloseHandle", "Uint", hProc)
   return   sTrayIcons
   }
GetTrayBar() {
   ControlGet, hParent, hWnd,, TrayNotifyWnd1  , ahk_class Shell_TrayWnd
   ControlGet, hChild , hWnd,, ToolbarWindow321, ahk_id %hParent%
   Loop {
      ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class Shell_TrayWnd
      If  Not   hWnd
      Break
      Else If   hWnd = %hChild%
         {
         idxTB := A_Index
         Break
         }
      }
   Return   idxTB
   }
StrX( H,  Bs="",BO=0,BT=1,   ES="",EO=0,ET=1,  ByRef N="" ) {
   Return SubStr(H,P:=(((Z:=StrLen(ES))+(X:=StrLen(H))+StrLen(Bs)-Z-X)?((T:=InStr(H,Bs,0,((BO
   <0)?(1):(BO))))?(T+BT):(X+1)):(1)),(N:=P+((Z)?((T:=InStr(H,ES,0,((EO)?(P+1):(0))))?(T-P+Z
   +(0-ET)):(X+P)):(X)))-P)
   }   ; By SKAN:   http://www.autohotkey.com/community/viewtopic.php?p=312116#p312116

ewemoa

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 2,845
    • View Profile
    • Donate to Member
Re: AHK_L tray code to clear orphaned icons that actually seems to work
« Reply #5 on: October 06, 2012, 07:02:02 PM »
Thanks for sharing this :up: