Tray icon does not disappear on killing process
Asked Answered
N

8

17

I have a window service for my application. When i stops that by killing process with task manager, the tray icon does not disappear. Is it a window bug or something else? Do we have a solution for that problem? Thanks in advance :).

Natheless answered 22/2, 2010 at 15:23 Comment(1)
Does this answer your question? NotifyIcon remains in Tray even after application closing but disappears on Mouse HoverPastorate
H
6

There is no solution to this problem. If you kill process with task manager, it does not receive termination notification, and hence can not remove its icon from the tray. Try avoiding killing process this way. You can use net start/stop to kill a service or services.msc GUI.

Hydantoin answered 22/2, 2010 at 15:25 Comment(0)
G
10

You can let the icon disappear by calling the Dispose()-method of the specified NotifyIcon-object. In most cases these Container-object isn't part of the tree of components in your application so it will not disappear by killing the proces. When the user moves over the icon, the icon doesn't find it parent so it dissapears. But by calling the Dispose-method, it disapeared at least in my applications. So:

//creating a NotifyIcon
NotifyIcon notifyicon = new NotifyIcon();
notifyicon.Text = "Text"; 
notifyicon.Visible = true; 
notifyicon.Icon = new Icon(GetType(),"Icon.ico");
//let it disappear
notifyicon.Dispose();
Gravy answered 22/2, 2010 at 15:33 Comment(8)
Thanks, It sounds nice but i dont know where to put that code. That will be great if you can help me with that.Natheless
I think you should define a method so when your application quits it will call that method. So if it is a Window-application (with a form). I think you will propably use the method Application.Run(yourForm); after the form is closed, the method is completed, so the main method will move on. If you have defined the notifyIcon in your main-class you can let it dispear after the Run-method. But of course I can't answer the question in general. You will need to find a thread that works when ending your application.Gravy
EDIT (I reread your question):if you add a method to the Process.Exited event and that method does the job, I think it should work, but I didn't tested it yet. Good luckGravy
Hi, I guess it should work for me. Thanks for making me a happy man :).Natheless
Hi, Its not working as none of my code part is getting hit on killing process. No luck yet :(.Natheless
Does the code works without killing the process but by for example closing the Form or something else, another way could be to put the icon in a way as an object intro the process space.Gravy
Hi, that is great, it just works, at least on XP... did know the problem as XP-Bug only till today.Aggravate
@Lalit, another thing you could do (but of course this isn't a elegant solution is when the program is loaded, start up another program that monitors your first program, when the first is closed, the other will make the icon disapear. If the second is killed, the first simply creates a new program. But of course such a way of working looks much as the behaviour of a virus.Gravy
H
6

There is no solution to this problem. If you kill process with task manager, it does not receive termination notification, and hence can not remove its icon from the tray. Try avoiding killing process this way. You can use net start/stop to kill a service or services.msc GUI.

Hydantoin answered 22/2, 2010 at 15:25 Comment(0)
H
6

Use this tool http://www.codeproject.com/Articles/19620/LP-TrayIconBuster

It iterates through ToolBarButtons in TrayNotifyWnd & NotifyIconOverflowWindow and removes those with null file names.

Hadley answered 10/7, 2013 at 15:12 Comment(2)
Perfect, I was looking for an automated way to handle this. This app can't be run "on demand" (it wants to remain as a persistent tray app). It also removes a couple of valid icons in my setup. But, the source code is provided so I should be able to adapt it to my needs.Toole
I tried this but for me it removes icons for some programs that are still running.Cheney
V
4

Move your mouse over the icon, and it will disappear. I've noticed this behavior in all versions of windows, including Win 7.

Venerate answered 22/2, 2010 at 15:24 Comment(4)
Yeah it works but i have to make it disappear by code. I mean there is some script my testing team is running to stop that service and i feel that they are actually killing process instead of quiting service gracefully. I have to find a solution for them (you know testing guys :D).Natheless
This is not exactly a fix. More like a dirty filthy hack.Mcchesney
This is a windows thing, the only suggestion I can think of is create a helper app (hidden) that has 1 simple purpose to monitor when the main app gets aborted unexpectedly (on a timer), if the first app goes down - then take an action, exactly what that action is - I really do not know.Venerate
Downvote because no answer, no hint to why no answer either... why is it upvoted so often?Aggravate
K
4

I often notice that too, with various applications. The death of the application is only noticed when you move the mouse over the icon.

I think the "bug" is with Windows, not your application. (I'm reluctant to call it a "bug", per se, because it was probably a conscious decision to leave this in. Explorer could check whether applications that registered icons are still running, but that might be too expensive.)

Kindliness answered 22/2, 2010 at 15:26 Comment(0)
O
4

If an application is forcefully terminated (e.g. through Task Manager), then Windows does not remove the notification icon. Windows Explorer doesn't even notice that the application has gone away until it attempts to send a message (usually a mouse movement message) to the window that owns the notification icon. At that point, Windows will remove the now dead icon from the notification area.

Given that you can't intercept TerminateProcess, there's nothing that your program can do about this by itself.

I guess that Windows Explorer could watch for the owner window being destroyed (as when the application quits unexpectedly), but it doesn't.

Even if the application is shut down gracefully, it must still remember to remove any of its notification icons. That is: if you don't call Shell_NotifyIcon(NIM_DELETE) (the equivalent of NotifyIcon.Dispose) when your application shuts down (even gracefully), the icon will remain there until the mouse moves over it.

Oh, and if this is a service process that's displaying the notification icon, be aware that session 0 isolation in Windows Vista and Windows 7 will break it.

Orectic answered 22/2, 2010 at 15:40 Comment(0)
P
2

You can move your mouse over it, or you can send a WM_MOUSEMOVE message to it.

Here is some sample code (tested on Windows 10):

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left, Top, Right, Bottom;
    }

    [DllImport("user32.dll")]
    static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr hWndChildAfter, string className, string? windowTitle);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, nuint wParam, nint lParam);

    const int WM_MOUSEMOVE = 0x0200;

    public static void RefreshTraybar()
    {
        RefreshHiddenTraybar();
        RefreshTraybarInTaskbar();
    }

    static void RefreshHiddenTraybar()
    {
        var hiddenTrayWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "NotifyIconOverflowWindow", null);
        var hiddenNotificationArea = FindWindowEx(hiddenTrayWnd, IntPtr.Zero, "ToolbarWindow32", null);
        RefreshArea(hiddenNotificationArea);
    }

    static void RefreshTraybarInTaskbar()
    {
        var trayInTaskbarWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "Shell_TrayWnd", null);
        var trayNotifyWnd = FindWindowEx(trayInTaskbarWnd, IntPtr.Zero, "TrayNotifyWnd", null);
        var sysPager = FindWindowEx(trayNotifyWnd, IntPtr.Zero, "SysPager", null);
        var trayNotificationArea = FindWindowEx(sysPager, IntPtr.Zero, "ToolbarWindow32", null);
        RefreshArea(trayNotificationArea);
    }

    static void RefreshArea(IntPtr area)
    {
        if (!GetClientRect(area, out var clientRect)) return;
            
        for (int x = 0; x < clientRect.Right; x += 10)
            for (int y = 0; y < clientRect.Bottom; y += 10)
                SendMessage(area, WM_MOUSEMOVE, 0, (y << 16) + x);
    }
Pharyngitis answered 19/5, 2022 at 18:46 Comment(0)
M
0

I've done it by handling the ThreadException event and disposing the tray icon in that event handler.

Mcchesney answered 22/2, 2010 at 15:53 Comment(3)
Hey will, control is not going on ThreadException on killing process, so it wont work :(.Natheless
@lalit well, if you're actually using a service (i.e., extends ServiceBase), you can override the Dispose method. It all depends on exactly what kind of application you have and where the tray icon is created.Mcchesney
@lalit Hmmm.... are you using a real service? (as in, extends ServiceBase)? Its hard to tell you what to do and where because we don't know exactly what kind of app you're developing and how you are constructing the TrayIcon and where you're storing it. Code would definitely help. If you're actually using a service and you create the TrayIcon in your service class (I'm not sure if that's even possible) you can drop the TrayIcon in the this.components collection and it will be disposed when the service is disposed. But I'm not sure if that's how you're doing it, hence gimme code.Mcchesney

© 2022 - 2024 — McMap. All rights reserved.