16

My program puts an icon in the system tray because the user may minimize to it. However, if the application crashes, or I stop the app from running in VS it leaves the icon in it until I hover over it with the mouse. Sometimes I'll look down there and there will be 10 or so icons.

I can I make sure the icon goes away?

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
Malfist
  • 31,179
  • 61
  • 182
  • 269
  • Does this answer your question? [NotifyIcon remains in Tray even after application closing but disappears on Mouse Hover](https://stackoverflow.com/questions/14723843/notifyicon-remains-in-tray-even-after-application-closing-but-disappears-on-mous) – T.Todua Jul 30 '20 at 07:28

6 Answers6

22

There is no way to do this. Windows does not poll your program to see if it's still alive. Therefore, your icon will stay in the system tray until you either tell it to leave (normal exit), or the user does something that initiates a call to your program (such as mouseover). Only then does the shell know that your program has died and it needs to clean up your icon.

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
  • So there's no event I can grab in case the program dies? – Malfist Oct 26 '09 at 20:35
  • No, there is no event. This is "normal" behavior...every app that has a system tray icon leaves its icon behind when it exits abnormally. – jrista Oct 26 '09 at 20:38
  • 1
    It's very unlikely that you will not have an opportunity to clean up you icon. AppDomain.ProcessExit is a pretty good event to listen to for process exit. Unless you call Environment.FailFast() it will likely be called even in 'catastrophic' circumstances – Jan Bannister Oct 26 '09 at 20:44
  • @Jan: I would hope that if you terminate the process (as through Task Manager), it would die instantly instead of running some cleanup code. I don't know if that's the case or not, but it fits the behavior I've observed. I would also assume that terminating an app through the debugger in VS would similarly kill it without running any additional code. – rmeador Oct 26 '09 at 21:38
  • 4
    Just because lots of programs suck (i.e. fail to do this properly) doesn't mean it isn't doable, nor that you shouldn't do it. See my answer for a viable solution - the #2 option I present should be doable in .NET, C, and C++ - any language that gives you access to process handle & the ability to wait for said handle to be signaled. – Mordachai Oct 27 '09 at 13:52
5

You have several options:

1) Write a root structured exception handler that ensures the destruction of the icon before exit. This one takes some effort - but you can basically add your own unhandled exception handler to Windows which will be called in the case of many forms of "boom" which will then allow you some last-ditch clean up opportunity.

2) Write a monitor application that sleeps on your main processes handle, and kills the icon when it wakes up (the main application has died). To make this latter scenario work well, you'll likely want the main process to NOT kill the icon itself - or you could create a way to tell the monitor app that it should exit w/o destroying the icon (have the monitor app sleep on both the process handle and a named event - and if woken by the event then it simply dies w/o cleaning up after the main app).

Mordachai
  • 9,412
  • 6
  • 60
  • 112
  • D'oh - I should have noted the language. Option #1 is available for C or C++, but I'm not sure that is available to a C# app - so you may be forced to do #2. – Mordachai Oct 26 '09 at 20:46
  • #2 is the more robust option, anyway. #1 would be no good if the process were killed in Task Manager, or as the OP mentioned, if one were to abruptly end a debug session. – P Daddy Oct 26 '09 at 20:52
3

Before you exit, set the NotifyIcon Visible property to false.

driis
  • 161,458
  • 45
  • 265
  • 341
3

You need to call Dispose on the NotifyIcon for it to leave the tray.

EDIT: There's an event you can hook into in your Program.cs. For all Windows apps, you'll have something like this:

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

The Application class has a few events you can take advantage of to know when your app dies:

        Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
        Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
BFree
  • 102,548
  • 21
  • 159
  • 201
  • 1
    The OP mentions that he sees the problem only when his application dies, or he kills it. In those situations, Dispose() won't be called. – Michael Petrotta Oct 26 '09 at 20:35
0

I don't know what happens when one kills the process, but if it crashes due to an exception, of course one can handle it. The way to do it best, depends on the type of application: Console, Forms, a service, ...

But in all cases, you should be able to use a try / finally structure in your Program.cs, and in the 'finally' section Dispose() the TrayIcon.

For example, in a Forms application, make your NotifyIcon (called TrayIcon in my example below) in your Form class public, and change the "Application.Run(new Form1())" line in Program.cs as follows:

Form form = new Form1();
try { Application.Run(form); }
finally { form.TrayIcon.Dispose(); }
Ronny D'Hoore
  • 752
  • 7
  • 9
-1

We can hide trayIcon before form closing. Add FormClosing Event

NotifyIcon ni;
...
...
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
     ni.Visible = false;
}
Borys Shobat
  • 258
  • 1
  • 3
  • 13