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)
End
Code: 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?