Click here to Skip to main content
14,868,300 members
Articles / Programming Languages / C#
Posted 16 Jul 2007


40 bookmarked


Rate me:
Please Sign up or sign in to vote.
4.91/5 (24 votes)
21 Dec 2014CPOL5 min read
A utility that removes phantom icons from the Icon Tray
Before After
Screenshot - LPTrayIconBuster1.gif Screenshot - LPTrayIconBuster2.gif


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 developing 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 while 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 and then to enumerate the buttons and get their file names, i.e. the filenames of the processes that created them. The final step is to delete the icons without filenames, i.e. 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 it enumerates all icons a first time looking for its own icon (more on that later). Next it enumerates all icons again and removes the ones without a file name associated to them. There are basically four source files. Those are 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.


This class has a single static method that removes the phantom icons. It can be called directly by any program that wishes to clean up the icons. Typically this would happen 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 returns the number of icons actually removed. It throws an exception if and when things go badly wrong.


This class represents some other process. It 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.


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.


The TrayIconBuster class deletes some windows. If anything goes wrong with that, chances are that too many things will disappear. While deleting icons is not fatal for Windows Explorer, there seems to be only one way to recover from it and that is by restarting Windows. We want to avoid that being necessary. As a safety measure, TrayIconBuster enumerates the icons twice:

  • In the first pass, it does not change or delete any icon; it just looks for the file names associated with them. 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 -- i.e. the ones without filenames -- 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 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 that it will perform the job it is intended for. Please feel free to report successes 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


  • 16 July, 2007 -- LP#TrayIconBuster 1.0 (first release)
  • 22 December, 2014 -- version 2.0 now supports 64-bit Windows (using two different data structures for toolbar buttons) and works on Windows 7 and Windows 8 (dealing with the new NotifyIconOverflowWindow. Warning: in order to operate properly on Win64, it must be built for "Any CPU".


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Luc Pattyn
Software Developer (Senior)
Belgium Belgium
I am an engineer with a background in electronics, software and mathematics.

I develop technical software, both for embedded systems and for desktop equipment. This includes operating systems, communication software, local networks, image processing, machine control, automation, etc.

I have been using all kinds of microcontrollers and microprocessors (Intel 4004/8080/8051/80386/Pentium, Motorola 680x/680x0/ColdFire/PowerPC, Microchip PIC, Altera NIOS, and many more), lots of programming languages (all relevant assemblers, Fortran, Basic, C, Java, C#, and many more), and different operating systems (both proprietary and commercial).

For desktop applications and general development tools I have been using both UNIX systems and Mac/MacOS for many years, but I have switched to x86-based PCs with Windows, Visual Studio and the .NET Framework several years ago.

I specialize in:
- cross-platform development (making software that runs on diverse hardware/OS combinations)
- instruction set simulation
- improving software performance, i.e. making sure the software runs the job at hand in as short a time as possible on the given hardware. This entails algorithm selection, implementation design, accurate measurements, code optimisation, and sometimes implementing virtual machines, applying SIMD technology (such as MMX/SSE), and more.

Comments and Discussions

SuggestionCycle icons backwards, so you don't have to adjust index Pin
Wilson Barbosa7-Mar-21 8:05
MemberWilson Barbosa7-Mar-21 8:05 
Praiseexactly what I needed... one minor issue Pin
Member 1473082818-May-20 15:59
MemberMember 1473082818-May-20 15:59 
SuggestionRequest - Alter Code To Remove Orphaned Balloon Tooltips Pin
Mark W. Stroberg6-Jul-19 21:20
MemberMark W. Stroberg6-Jul-19 21:20 
QuestionRunning in background Pin
user_cp5-Oct-18 22:26
Memberuser_cp5-Oct-18 22:26 
QuestionPlatform Target can be x86 if using .NET 4.0+ Pin
Member 133947306-Sep-17 6:10
MemberMember 133947306-Sep-17 6:10 
QuestionCan't believe I haven't read this before! Pin
R. Giskard Reventlov23-Nov-16 10:42
MemberR. Giskard Reventlov23-Nov-16 10:42 
Questionparameter Pin
Member 1232759914-Feb-16 21:33
MemberMember 1232759914-Feb-16 21:33 
AnswerRe: parameter Pin
Luc Pattyn15-Feb-16 1:31
sitebuilderLuc Pattyn15-Feb-16 1:31 
QuestionVersion 2.0 Pin
Luc Pattyn21-Dec-14 15:09
sitebuilderLuc Pattyn21-Dec-14 15:09 
AnswerRe: Version 2.0 Pin
Garth J Lancaster21-Dec-14 19:52
mveGarth J Lancaster21-Dec-14 19:52 
BugWerkt niet onder Windows 7 ??? Pin
Member 1130789013-Dec-14 1:16
MemberMember 1130789013-Dec-14 1:16 
GeneralRe: running under Windows 7 or 8 Pin
Luc Pattyn13-Dec-14 2:46
sitebuilderLuc Pattyn13-Dec-14 2:46 
GeneralMy vote of 5 Pin
Juergen Brueckler3-Jul-12 21:53
MemberJuergen Brueckler3-Jul-12 21:53 
QuestionHelp - Unexpected Window appears Pin
malcolm4621-Feb-11 17:56
Membermalcolm4621-Feb-11 17:56 
AnswerRe: Help - Unexpected Window appears Pin
Luc Pattyn22-Feb-11 1:49
sitebuilderLuc Pattyn22-Feb-11 1:49 
GeneralRe: Help - Unexpected Window appears Pin
malcolm4622-Feb-11 16:17
Membermalcolm4622-Feb-11 16:17 
AnswerRe: Help - Unexpected Window appears Pin
Luc Pattyn23-Feb-11 7:20
sitebuilderLuc Pattyn23-Feb-11 7:20 
GeneralRe: Help - Unexpected Window appears Pin
malcolm4623-Feb-11 15:17
Membermalcolm4623-Feb-11 15:17 
GeneralMy vote of 5 Pin
Mike Fullarton31-Aug-10 2:11
MemberMike Fullarton31-Aug-10 2:11 
GeneralWindows 7 [modified] Pin
Luc Pattyn27-Aug-09 11:31
sitebuilderLuc Pattyn27-Aug-09 11:31 
GeneralRe: Windows 7 [modified] Pin
mmbrian10-Jul-13 5:07
Membermmbrian10-Jul-13 5:07 
GeneralRe: Windows 7 [modified] Pin
Luc Pattyn10-Jul-13 12:56
sitebuilderLuc Pattyn10-Jul-13 12:56 
GeneralRe: Windows 7 [modified] Pin
mmbrian11-Jul-13 4:15
Membermmbrian11-Jul-13 4:15 
GeneralIcon removed, Empty space left in Systray Pin
mark_me11-Aug-09 9:39
Membermark_me11-Aug-09 9:39 
AnswerRe: Icon removed, Empty space left in Systray Pin
Luc Pattyn11-Aug-09 14:56
sitebuilderLuc Pattyn11-Aug-09 14:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.