Re: How to remove systray icon?
Posted: Wed Feb 17, 2010 12:58 pm
				
				I don't understand that code much srod, but could this code be modified to remove the trayicon of a program killed with killprogram?
			http://www.purebasic.com
https://www.purebasic.fr/english/
Of course it won't close it in such circumstances. You should close it via some macro keystrokes then, using whatever key combo actually exits the app. Do a search for "SendKeys" here for the code.whertz wrote:sending it Alt+F4 minimizes it, it is just the way the program works
Only if you can identify the handle of the relevant icon which you would probably need to do by enumerating all the taskbar icons. The only way to do this is to make some inter-process calls to the explorer process in order to retrieve the individual toolbar buttons data etc. Quite fiddly (but very possible). Whilst enumerating the various buttons you would retrieve each icons NOTIFYICONDAT structure and examine the hWnd field etc. Once found, you then delete the button with Shell_NotifyIcon_().whertz wrote:I don't understand that code much srod, but could this code be modified to remove the trayicon of a program killed with killprogram?
Sounds way too complicated.srod wrote:Only if you can identify the handle of the relevant icon which you would probably need to do by enumerating all the taskbar icons. The only way to do this is to make some inter-process calls to the explorer process in order to retrieve the individual toolbar buttons data etc. Quite fiddly (but very possible). Whilst enumerating the various buttons you would retrieve each icons NOTIFYICONDAT structure and examine the hWnd field etc. Once found, you then delete the button with Shell_NotifyIcon_().whertz wrote:I don't understand that code much srod, but could this code be modified to remove the trayicon of a program killed with killprogram?
It is too much work and too reliant on using FindWindow_() and on things which probably shouldn't be messed with (e.g. firing messages at the relevant explorer toolbar etc.)
If I were you I'd follow UserOfPure's advice.
No, it's like srod said about getting the handle (see his post). I just want to make it clear, it is not any program I have written that I am trying to remove the icon after I kill it, it is an external program.skywalk wrote:@whertz
I am kinda confused?
Did the code I submitted work for you?
It works for me running Windows XP sp3, PB 4.41.
Code: Select all
Structure m_NOTIFYICONDATA
  cbSize.i
  hwnd.i
  uId.i
  uFlags.i
  uCallBackMessage.i
  hIcon.i
  szTip.s{64}
EndStructure
ImportC "SHELL32.LIB" 
  Shell_NotifyIcon_.i(dwMessage.i, pnid.i) As "_Shell_NotifyIconA" 
EndImport
Define.i hWnd, hIcon, ri
Define.s Prog2run
Define.m_NOTIFYICONDATA nid  
prog2run = "c:\windows\notepad.exe"
hwnd = GetDesktopWindow_()
hicon = ExtractIcon_(0,prog2run,0)
With nid
  \cbSize = SizeOf(nid)
  \hWnd = hWnd
  \uId = #Null
  \uFlags = #NIF_ICON | #NIF_TIP | #NIF_MESSAGE
  \uCallBackMessage = #WM_MOUSEMOVE
  \hIcon = hicon
  \szTip = "Some Text Here" + #NULL$
EndWith
ri = RunProgram(Prog2run, #NULL$, #NULL$, #PB_Program_Open)
Shell_NotifyIcon_(#NIM_ADD, nid)
  Debug "...Hold mouse over SysTray icon now..."
  Delay(5000)
  Debug "...Attempting to remove SysTray icon..."
  Debug ""
Shell_NotifyIcon_(#NIM_DELETE, nid)
  Debug "...Quitting in 3 sec..."
DestroyIcon_(hIcon)
  Delay(3000)
KillProgram(ri):CloseProgram(ri)
EndCode: Select all
; Enumerate Systray Icons
; netmaestro October 2009
; Tested on XP and Vista, doesn't work for Windows 7
; Just for fun
; Modified by RASHAD 17/02/2010
; Tested on XP x86 ,Vista x86 and Win 7 X64 PB x64
; Have fun
Structure TRAYOWNER
  bitmap.l
  hwnd.s
  filename.s
EndStructure
Structure TRAYDATA
    hwnd.l                
    uID.l             
    uCallbackMessage.i    
    Reserved.l[2]      
    hIcon.l                
EndStructure
Structure _TBBUTTON
    iBitmap.l 
    idCommand.l
    fsState.b 
    fsStyle.b 
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    bReserved.b[6]
CompilerElse
    bReserved.b[2]
CompilerEndIf
    dwData.i 
    iString.i 
EndStructure
Global NewList TrayIcons.TRAYOWNER()
Procedure Enumerate_TrayIcons()
  lib = OpenLibrary(#PB_Any, "psapi.dll")
  
  ; Find the System Tray Icon Toolbar
  Protected hwnd
  hWnd = FindWindow_("Shell_TrayWnd", #Null)
  If hWnd
    hWnd = FindWindowEx_(hWnd, #Null, "TrayNotifyWnd", #Null)
    If hWnd
      hWnd = FindWindowEx_(hWnd,#Null, "SysPager", #Null)
      If hWnd 
        hTray = FindWindowEx_(hWnd, #Null, "ToolbarWindow32", #Null)
      Else
        ProcedureReturn 0
      EndIf
    Else
      ProcedureReturn 0
    EndIf
  Else
    ProcedureReturn 0
  EndIf
  
  count = SendMessage_(hTray, #TB_BUTTONCOUNT, 0, 0)
  
  Dim button._TBBUTTON(count)
  Dim button_td.TRAYDATA(count)  
  
  dwExplorerThreadId=GetWindowThreadProcessId_(hTray, @dwExplorerProcessId)
  hProc = OpenProcess_(#PROCESS_ALL_ACCESS, #False, dwExplorerProcessId)
  *lpData = VirtualAllocEx_(hProc, #Null, SizeOf(_TBBUTTON)*count, #MEM_COMMIT, #PAGE_READWRITE)
  
  For i = 0 To count-1
    SendMessage_(hTray, #TB_GETBUTTON, i, *lpData+i*SizeOf(_TBBUTTON) )
    ReadProcessMemory_(hProc, *lpData+(i*SizeOf(_TBBUTTON)), @button._TBBUTTON(i), SizeOf(_TBBUTTON), #Null)    
    ReadProcessMemory_(hProc, button(i)\dwData, @button_td.TRAYDATA(i), SizeOf(TRAYDATA), #Null)
    ;The error 299 is ERROR_PARTIAL_COPY
    
    thisbmp = button_td(i)\hIcon    
    thishwnd = button_td(i)\hwnd    
    thisfilename$ = Space(#MAX_PATH)
    GetWindowThreadProcessId_(thishwnd, @thisprocessID.i)
    hthisProcess = OpenProcess_(#PROCESS_ALL_ACCESS, #False, thisprocessID )              ;|#PROCESS_QUERY_INFORMATION
    CallFunction(lib, "GetProcessImageFileNameA", hthisProcess, @thisfilename$, 255)
    CloseHandle_(hthisProcess)
    
    AddElement(TrayIcons())
    TrayIcons()\hwnd = Str(thishwnd)
    trayIcons()\filename = thisfilename$
    TrayIcons()\bitmap = thisbmp
  Next
  
  VirtualFreeEx_(hProc, *lpData, #Null, #MEM_RELEASE)
  CloseHandle_(hProc)
  If IsLibrary(lib) : CloseLibrary(lib) : EndIf
  
EndProcedure
Enumerate_TrayIcons()
OpenWindow(0,0,0,600,400,"System Tray Icon Owners",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ListIconGadget(0,0,0,600,400,"Icon", 60, #PB_ListIcon_GridLines)
AddGadgetColumn(0, 1, "Owner hWnd",100)
AddGadgetColumn(0, 2, "Owner Location",250)
AddGadgetColumn(0, 3, "Icon hWnd",200)
ForEach TrayIcons()
  AddGadgetItem(0,-1, Chr(10)+TrayIcons()\hwnd +Chr(10)+TrayIcons()\filename+Chr(10)+Str(TrayIcons()\bitmap),TrayIcons()\bitmap)
Next
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
No, there are no other windows, when the program gets sent a close command it minimizes instead. Like msn messenger etc. does when you close the window, it doesn't really close it's still running on the taskbar.srod wrote:All the work is done with that execellent code Rashad. All whertz has to do is examine the window handles and match up the one belonging to the application he is messing around with and then use Shell_NotifyIcon_() etc.![]()
Still, I think this is too much work for such a simple thing.
@Whertz : could you be sending #WM_CLOSE to the wrong window? Could the window you are sending the message to have a parent? Does the application have other windows?