Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

NoTrayOrphans()


  • Please log in to reply
15 replies to this topic
Cragaha
  • Members
  • 265 posts
  • Last active: Jan 04 2016 02:24 AM
  • Joined: 19 Nov 2010
Credit to Sean

#NoTrayIcon
#NoEnv
#Persistent
#SingleInstance force
DetectHiddenWindows, On
SetWorkingDir %A_ScriptDir%



NoTrayOrphans()
ExitApp
Return

NoTrayOrphans() {
    TrayInfo:= TrayIcons(sExeName,"ahk_class Shell_TrayWnd","ToolbarWindow32" . GetTrayBar()) "`n"
        . TrayIcons(sExeName,"ahk_class NotifyIconOverflowWindow","ToolbarWindow321")
    Loop, Parse, TrayInfo, `n
        {
        ProcessName:= StrX(A_Loopfield, "| Process: ", " |")
        ProcesshWnd:= StrX(A_Loopfield, "| hWnd: ", " |")
        ProcessuID := StrX(A_Loopfield, "| uID: ", " |")
        If !ProcessName && ProcesshWnd
            RemoveTrayIcon(ProcesshWnd, ProcessuID)
        }
    }
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="",ES="",Tr=1,ByRef OS=1) {
    return,(SP := InStr(H,BS,0,OS)) && (L := InStr(H,ES,0,SP+StrLen(BS))) && (OS := L + StrLen(ES)) ? SubStr(H,SP := Tr ? SP + StrLen(BS) : SP ,(Tr ? L : L + StrLen(ES))-SP) : ""
    }


guest3456
  • Members
  • 1704 posts
  • Last active: Nov 19 2015 11:58 AM
  • Joined: 10 Mar 2011
What is a tray orphan?

gwarble
  • Members
  • 624 posts
  • Last active: Aug 12 2016 07:49 PM
  • Joined: 23 May 2009
Nice script, thanks for sharing

guest: those left-behind tray icons when processes are forcibly ended, or poorly coded exit routine

they disappear when mouse-over'ed, this provides a programmatic solution to get rid of them

Cragaha
  • Members
  • 265 posts
  • Last active: Jan 04 2016 02:24 AM
  • Joined: 19 Nov 2010
Thanks gwarble Posted Image

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Nice Nazzal :)
I might want to rewrite NoTrayOrphans() as a standalone version.

What is a tray orphan?


The icons visible in TNA after its associated process dies prematurely.

The following script will leave its TNA Icon orphaned.
Process, Close, % DllCall("GetCurrentProcessId")


Cragaha
  • Members
  • 265 posts
  • Last active: Jan 04 2016 02:24 AM
  • Joined: 19 Nov 2010
That would be nice SKAN, would you post a link to yours here once done? Posted Image
I have been trying to find a way to get rid of those orphans for a while, this works on XP and 7.
Thing is on Windows 7 tray icons could be hidden in NotifyIconOverflowWindow window, so you might want to look into that too.

guest3456
  • Members
  • 1704 posts
  • Last active: Nov 19 2015 11:58 AM
  • Joined: 10 Mar 2011

Nice script, thanks for sharing

guest: those left-behind tray icons when processes are forcibly ended, or poorly coded exit routine

they disappear when mouse-over'ed, this provides a programmatic solution to get rid of them



ahhh! i know those! cool

gwarble
  • Members
  • 624 posts
  • Last active: Aug 12 2016 07:49 PM
  • Joined: 23 May 2009
Hehe yup, i bet any windows user does...
good descriptive name (tray orphans that is, dont know if thats what they're called anywhere but it works)

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Dear Nazzal, :)

There should be no blank parameters in function call: ProcessName := StrX(Item, "| Process:", 0, 11, "|", 1, 2 )
Runs fine in AHK_Lw though.

Cragaha
  • Members
  • 265 posts
  • Last active: Jan 04 2016 02:24 AM
  • Joined: 19 Nov 2010
Thanks SKAN, fixed, although I used 1 instead of 0 Posted Image
I also shortened the whole thing.

MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009
Just trying it now. Seems fine. Any prohibition to including exe in a zip so I could just launch NoTrayOrphans.exe from my script? Leaving tray icons behind has to be one of the most annoying side effects for users. :)

Credit for program in included Readme.txt OK?

"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


Cragaha
  • Members
  • 265 posts
  • Last active: Jan 04 2016 02:24 AM
  • Joined: 19 Nov 2010
Hello MilesAhead,
No problem, here is an already compiled and compressed executable with no icon to keep it as small as possible
NoTrayOrphans.exe 319 KB

MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009
Thank you very much. Killing those orphans dead will make even my own home use hacks much more fun. :)

"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009
Hmm, I'm running into something weird. If I compile using AHK_L from the code below, it seems to work every time. If I have my program call the compressed no icon version you attached, I have to mouse over every time. I've tried it using 10 second delay, and 5 minute delay(for closing an app sitting in the tray) and in either case the compressed version forces me to mouse over.

I'm using Windows Seven 32 bit no SP.

edit: additional info. I compiled with no compression and standard green A icon. Seems to work every time. Of course at this point I've only tested a few times. But switching back to the compressed version I have to mouse over every time.

#NoTrayIcon
#SingleInstance force
DetectHiddenWindows, On

NoTrayOrphans()
ExitApp
Return

NoTrayOrphans() {
   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)
      }
   }
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

"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


mikek
  • Members
  • 161 posts
  • Last active: Nov 09 2015 05:02 PM
  • Joined: 21 Nov 2008

Thank you, Nazzal. This solved a problem I had.

 

- Mike