Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Removing tray icon after having killed its process

196 views
Skip to first unread message

Matthieu Gaillet

unread,
May 3, 2004, 4:09:06 AM5/3/04
to
Hi group,

I need to remove the tray icon left in the tray by a process I killed using
the TerminateProcess provided in the WMI interface. I know I should send the
WM_QUIT message rather than WM_CLOSE, but I don't want the exit confirmation
window of the process to appear.

I code using VB6.

Thanks for your help.

--
Matt


Björn Holmgren

unread,
May 3, 2004, 7:55:02 AM5/3/04
to
"Matthieu Gaillet" <mg@~REMOVE-ME~evercom.be> wrote in message
news:ujTLsXOM...@TK2MSFTNGP10.phx.gbl...


Hi Matt,

This may not be the most elegant solution, but it works.

First, I use nested FindWindowEx calls to get a handle to the
ToolbarWindow32 that contains the icons. Notice that the window hierarchy is
a little bit different in XP compared to W2K. Then, I call GetWindowRect to
get the coordinates of the window. Finally, using PostMessage, I post a
WM_MOUSEMOVE message for each point along a horizontal line through the
middle of the window. This simulates moving the mouse across the entire task
tray.

If you want to support other operating systems, I suggest you use Spy++ to
investigate the window hierarchy, class names and titles. You can then add a
case clause for the new OS.

'----------
Private Const WM_MOUSEMOVE = &H200

Private Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long
szCSDVersion As String * 128
End Type

Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type

Private Declare Function GetVersionEx Lib "kernel32" Alias _
"GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long
Private Declare Function FindWindowEx Lib "user32" Alias _
"FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, _
ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetWindowRect Lib "user32" ( _
ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function PostMessage Lib "user32" Alias _
"PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long

Private Sub RefreshTrayWnd()
Dim osv As OSVERSIONINFO
Dim hwnd As Long
Dim r As RECT
Dim x As Long

osv.dwOSVersionInfoSize = Len(osv)
Call GetVersionEx(osv)

Select Case (osv.dwMajorVersion * 10) + osv.dwMinorVersion
Case 50 ' Windows 2000
hwnd = FindWindowEx(FindWindowEx(FindWindowEx(0, 0, _
"Shell_TrayWnd", ""), 0, "TrayNotifyWnd", ""), 0, _
"ToolbarWindow32", "")
Case 51, 52 ' Windows XP or Windows Server 2003
hwnd = FindWindowEx(FindWindowEx(FindWindowEx( _
FindWindowEx(0, 0, "Shell_TrayWnd", ""), 0, _
"TrayNotifyWnd", ""), 0, "SysPager", ""), 0, _
"ToolbarWindow32", "Notification Area")
Case Else ' Other OS (not supported)
Exit Sub
End Select
MsgBox hwnd
Call GetWindowRect(hwnd, r)
For x = r.Left To r.Right
Call PostMessage(hwnd, WM_MOUSEMOVE, 0, _
((r.Bottom - r.Top) \ 2) * &HFFFF + x - r.Left)
Next
End Sub
'----------

--
Björn Holmgren
Guide Konsult AB


Björn Holmgren

unread,
May 3, 2004, 7:56:30 AM5/3/04
to
"Björn Holmgren" <bjo...@hotmail.com> wrote in message
news:sqqlc.42744$zm5....@nntpserver.swip.net...

> End Select
> MsgBox hwnd
> Call GetWindowRect(hwnd, r)


Ooops! Left a msgbox in there. Just remove it.

Juergen Thuemmler

unread,
May 3, 2004, 7:51:47 AM5/3/04
to
> I need to remove the tray icon left in the tray by a process I killed
using
> the TerminateProcess provided in the WMI interface. I know I should send
the
> WM_QUIT message rather than WM_CLOSE, but I don't want the exit
confirmation
> window of the process to appear.

Not easy. The simplest way wold be to move the mouse by code (mouse_event())
across
the notify window, so that it refreshes itself. Assumed the notify area is a
toolbar, you can
remove the button (icon) using the TB_DELETEBUTTON message, but where to get
the
button index? Normally, you'll detect it comparing the (tooltip)text of the
button, but this
requires to hook into the explorer's thread using a standard DLL and cannot
be done with VB.

Juergen.


J French

unread,
May 3, 2004, 7:55:43 AM5/3/04
to
On Mon, 3 May 2004 10:09:06 +0200, "Matthieu Gaillet"
<mg@~REMOVE-ME~evercom.be> wrote:

>Hi group,
>
>I need to remove the tray icon left in the tray by a process I killed using
>the TerminateProcess provided in the WMI interface. I know I should send the
>WM_QUIT message rather than WM_CLOSE, but I don't want the exit confirmation
>window of the process to appear.

I find that WM_QUIT does not work for me

However WM_CLOSE does seem to work reliably

TerminateProcess is evil - its downsides are scary

Although WM_CLOSE is not supposed to have any parameters, I'll bet it
does have some.

Getting rid of the tray icon (comically) is generally done by
programatically waving the mouse pointer over it.

Matthieu Gaillet

unread,
May 3, 2004, 8:27:16 AM5/3/04
to
Hi J

> TerminateProcess is evil - its downsides are scary

What do you mean ? I found it was the most easy way to terminate my process
: here is the snippet :

For Each Process In GetObject("winmgmts:").execquery("Select * from
WIN32_PROCESS WHERE Caption = 'MLM.exe'")
Process.Terminate (0)
Next

Nice, isn't it ? Even not a call to the win API :-)
What are those downsides you talked about ?

Matt


"J French" <ere...@nowhere.com> wrote in message
news:40963284...@news.btclick.com...

Matthieu Gaillet

unread,
May 3, 2004, 8:46:19 AM5/3/04
to
Hi Björn !

Your solution, though not being the most elegant indeed is well coded and
documented. And furhermore, it works without changing a line !
Thank you so much for providing me a so quick and efficient solution !

Thanks to all the group for suggesting me other ways to do it. Juergen
probably has the most elegant solution but I don't have enough capabilities
to code it and the tool is too small to justify such a development. Thanks
anyway !

Bye bye, long life to the newsgroups

Matt

"Björn Holmgren" <bjo...@hotmail.com> wrote in message
news:sqqlc.42744$zm5....@nntpserver.swip.net...

MikeD

unread,
May 3, 2004, 9:12:59 AM5/3/04
to

"Matthieu Gaillet" <mg@~REMOVE-ME~evercom.be> wrote in message
news:OaVb8nQ...@TK2MSFTNGP09.phx.gbl...

> Hi J
>
> > TerminateProcess is evil - its downsides are scary
>
> What do you mean ? I found it was the most easy way to terminate my
process
> : here is the snippet :
>
> For Each Process In GetObject("winmgmts:").execquery("Select *
from
> WIN32_PROCESS WHERE Caption = 'MLM.exe'")
> Process.Terminate (0)
> Next
>
> Nice, isn't it ? Even not a call to the win API :-)
> What are those downsides you talked about ?

Not nice. Dangerous would be more accurate a description.

You're just killing the process and not letting it close down properly. This
could have many negative side affects. For example, if the process has open
files, those files won't get saved and may not close properly, thereby
leaving them corrupted. It could also result in Windows not reclaiming
memory, or not releasing system resources or freeing devices the process may
have been using. TerminateProcess is a last resort type of thing when
nothing else works.

Mike


Björn Holmgren

unread,
May 3, 2004, 9:20:41 AM5/3/04
to
Matt,

Glad you liked it. Unfortunately, there's a tiny typo in my code that you
need to correct. On the following line:

Call PostMessage(hwnd, WM_MOUSEMOVE, 0, _
((r.Bottom - r.Top) \ 2) * &HFFFF + x - r.Left)

...the &HFFFF is supposed to place the vertical position in the high-order
word, but of course it should be &H10000 instead.


--
Björn Holmgren
Guide Konsult AB

"Matthieu Gaillet" <mg@~REMOVE-ME~evercom.be> wrote in message
news:uZnUmyQM...@TK2MSFTNGP10.phx.gbl...

J French

unread,
May 3, 2004, 9:39:53 AM5/3/04
to
On Mon, 3 May 2004 14:27:16 +0200, "Matthieu Gaillet"
<mg@~REMOVE-ME~evercom.be> wrote:

>Hi J
>
>> TerminateProcess is evil - its downsides are scary
>
>What do you mean ? I found it was the most easy way to terminate my process
>: here is the snippet :
>
> For Each Process In GetObject("winmgmts:").execquery("Select * from
>WIN32_PROCESS WHERE Caption = 'MLM.exe'")
> Process.Terminate (0)
> Next
>
>Nice, isn't it ? Even not a call to the win API :-)
>What are those downsides you talked about ?

I have no idea what you are using

TerminateProcess is a core Windows API

Process.Terminate is some method of something I would prefer not to
use


Bob Butler

unread,
May 3, 2004, 9:56:58 AM5/3/04
to
"J French" <ere...@nowhere.com> wrote in message
news:40964ad4...@news.btclick.com

> On Mon, 3 May 2004 14:27:16 +0200, "Matthieu Gaillet"
> <mg@~REMOVE-ME~evercom.be> wrote:
>
>> Hi J
>>
>>> TerminateProcess is evil - its downsides are scary
>>
>> What do you mean ? I found it was the most easy way to terminate my
>> process
>>> here is the snippet :
>>
>> For Each Process In GetObject("winmgmts:").execquery("Select
>> * from WIN32_PROCESS WHERE Caption = 'MLM.exe'")
>> Process.Terminate (0)
>> Next
>>
>> Nice, isn't it ? Even not a call to the win API :-)
>> What are those downsides you talked about ?
>
> I have no idea what you are using

WMI

> TerminateProcess is a core Windows API
>
> Process.Terminate is some method of something I would prefer not to
> use

It ends up being an OO approach to calling TerminateProcess; I've got a
couple of things that use this but only for killing known virus/spyware-type
apps.

--
Reply to the group so all can participate
VB.Net... just say "No"

0 new messages