Article: LP#TrayIconBuster

Home Page


Consultancy

  • Service Vouchers
  • Escrow Service

Shop



Programming
  • Articles
  • Tools
  • Links

Search

 

Contact

 

PHPinfo


$_SERVER







A utility that removes phantom icons from the Icon Tray

category 'tool', language C#, created 16-Jul-2007, version V1.0, by Luc Pattyn

This article also appeared on the CodeProject.


License: The author hereby grants you a worldwide, non-exclusive license to use and redistribute the files and the source code in the article in any way you see fit, provided you keep the copyright notice in place; when code modifications are applied, the notice must reflect that. The author retains copyright to the article, you may not republish or otherwise make available the article, in whole or in part, without the prior written consent of the author.

Disclaimer: This work is provided as is, without any express or implied warranties or conditions or guarantees. You, the user, assume all risk in its use. In no event will the author be liable to you on any legal theory for any special, incidental, consequential, punitive or exemplary damages arising out of this license or the use of the work or otherwise.


Download exe - 9 KB

Download source - 25 KB

Before After
Icon Tray while debugging something Icon Tray while debugging something, with TrayIconBuster present

Introduction

A lot of programs install a NotifyIcon in the Icon Tray. Your system probably shows icons for Volume Control, Task Manager, Network Connections, and many more.

When a process installs a NotifyIcon and then exits without disposing of it, the icon remains present until you move the mouse pointer over it, making it suddenly disappear. A lot of such phantom icons may pile up when developping a new application, that installs a NotifyIcon but exits due to a fatal exception or a debug session being stopped in the middle.

This utility will take care of Tray Icon clean-up automatically.

The Icon Tray

The Icon Tray is one of many windows managed by the Windows Explorer; it is in fact a toolbar holding a lot of buttons. Some of these buttons are hidden, others are visible. For each button the Explorer holds a "process image name" which is the filename of the process that created the NotifyIcon.

There is no direct support for manipulating the Icon Tray in the .NET FrameWork, so we need a lot of P/Invoke stuff to call Win32 functions, first to locate the right toolbar, then to enumerate the buttons and get their file names (i.e. the filenames of the processes that created them), finally to delete the icons without filename (the filename gets replaced by null when the process exits).

The program

The program is simple. It does not show a Form, it simply shows yet another NotifyIcon. It offers a ContextMenu with three MenuItems: periodic run (runs every 5 seconds, checked by default), run now (for an immediate single run), and quit.

When the TrayIconBuster attempts to remove phantom icons, it first locates the correct ListView, then enumerates all icons a first time looking for its own icon (more on that later), then enumerates all icons again and removes the ones without a file name associated to them.

There basically are four source files: the main Form, the TrayIconBuster, and two help classes: LP_Process and LP_Pinner.

Main Form

Yes there actually is a main form, by default it is invisible. One could change the source code to make it visible, then it would simply hold a single button, equivalent to the "run now" item of the ContextMenu

TrayIconBuster

This class has a single static method that removes the phantom icons. It could be called directly by any program that wishes to clean up the icons (typically when the application starts up and wants to remove its own icons from a previous run).

		public static uint RemovePhantomIcons() {...}

The method attempts to remove all phantom icons, and it returns the number of icons actually removed; it throws an exception if and when things go badly wrong.

LP_Process

This class represents some other process and supports reading (and writing) its memory. It is used in conjunction with those Win32 functions that have pointers as parameters: since these pointers need to be valid in the other process, special steps have to be taken to get valid pointers in the first place, and to copy data to and from those locations from/to our own memory map.

LP_Pinner

This class is used by LP_Process to pin down a buffer, so the garbage collector is not able to move it around. This is sometimes necessary when pointers are used, as is the case when LP_Process performs a read or write operation crossing process boundaries.

Safety

The TrayIconBuster class deletes some windows; if anything goes wrong with that, chances are too many things disappear. While deleting icons is not fatal for Windows Explorer, there seems only one way to recover from it and that is by restarting Windows; we want to avoid that to be necessary.

As a safety measure, TrayIconBuster enumerates the icons twice:

  • In the first pass it does not change nor delete any icon, it just looks for the file names associated with them, more in particular it tries to find one ending on ".exe" as a sanity check.
  • If the first pass is successful, a second pass is started and only now phantom icons (the ones without filename) are removed. So if, for whatever reason, not a single filename is retrieved, the second pass will not be launched and all icons remain as they were.

The program has been tested on a 32-bit version of Windows XP; it has not been tested on other versions of Windows (such as Vista), and it has not been tested on any 64-bit Windows version. Thanks to the safety precautions we believe it is safe to try and run it on those systems as well, but we can not guarantee it then will perform the job it is intended for.

Please feel free to report success or problems on any Windows version...

Points of interest

Some of the following items relate to recent topics on one of the CodeProject message boards:

  • read or write memory belonging to another process;
  • apply the "using statement" to automatically have Dispose() called when the statement block is exited;
  • use some GC methods to temporarily pin down a buffer in memory;
  • have a global try-catch construct in the static Main() method.
  • Form1.cs also contains code to convert a JPEG image into an icon file.

History

  • LP#TrayIconBuster 1.0 (first release).


Perceler

Copyright © 2012, Luc Pattyn

Last Modified 21-May-2025