Omar Kooheji
Omar Kooheji

Reputation: 55770

Why am I seeing multiple Systray Icons?

I've added a Notify Icon to my app, and quite often I see up to 3 copies of the notify icon in my systray. is there a reason for this?

is there a way to stop it from happening.

Often this persists after my app has closed, untill I mose over to the systray and the systray expands and collapses snd then they all disapear.

Upvotes: 13

Views: 9600

Answers (4)

Chris W
Chris W

Reputation: 1712

This should work when you normally close the application:

// in form's constructor
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);

private void OnApplicationExit(object sender, EventArgs e)
{
    try
    {
        if (notifyIcon1!= null)
        {
            notifyIcon1.Visible = false;
            notifyIcon1.Icon = null;
            notifyIcon1.Dispose();
            notifyIcon1= null;
        }
    }
    catch { }
}

When you stop the App from Visual Studio stop debug button - the process is killed and no dispose events are fired.

Upvotes: 0

Jeff
Jeff

Reputation: 21

What I did:

  1. Create a class library that updates the system tray.

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    namespace SystrayUtil
    {
        internal enum MessageEnum
        {
            WM_MOUSEMOVE = 0x0200,
            WM_CLOSE = 0x0010,
        }
    
        internal struct RECT
        {
            internal int Left;
            internal int Top;
            internal int Right;
            internal int Bottom;
    
            internal RECT(int left, int top, int right, int bottom)
            {
                Left = left;
                Top = top;
                Right = right;
                Bottom = bottom;
            }
        }
    
        public sealed class Systray
        {
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, IntPtr lpszWindow);
    
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int message, uint wParam, long lParam);
    
            [DllImport("user32.dll", SetLastError = true)]
            private static extern bool GetClientRect(IntPtr hWnd, out RECT usrTray);
    
            public static void Cleanup()
            {
                RECT sysTrayRect = new RECT();
                IntPtr sysTrayHandle = FindWindow("Shell_TrayWnd", null);
                if (sysTrayHandle != IntPtr.Zero)
                {
                    IntPtr childHandle = FindWindowEx(sysTrayHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero);
                    if (childHandle != IntPtr.Zero)
                    {
                        childHandle = FindWindowEx(childHandle, IntPtr.Zero, "SysPager", IntPtr.Zero);
                        if (childHandle != IntPtr.Zero)
                        {
                            childHandle = FindWindowEx(childHandle, IntPtr.Zero, "ToolbarWindow32", IntPtr.Zero);
                            if (childHandle != IntPtr.Zero)
                            {
                                bool systrayWindowFound = GetClientRect(childHandle, out sysTrayRect);
                                if (systrayWindowFound)
                                {
                                    for (int x = 0; x < sysTrayRect.Right; x += 5)
                                    {
                                        for (int y = 0; y < sysTrayRect.Bottom; y += 5)
                                        {
                                            SendMessage(childHandle, (int)MessageEnum.WM_MOUSEMOVE, 0, (y << 16) + x);
                                        }
                                    }
                                }
                            }
                        }
                    } 
                }
            }
        }
    }
    
  2. Copy the dll to "%ProgramFiles%\Microsoft Visual Studio x.x\Common7\IDE\PublicAssemblies\SystrayUtil.dll"

    Where x.x is the version number of Visual Studio

  3. Record a macro and save it

  4. Edit the macro

    Add a reference to the created dll.

    Add Imports SystrayUtil to the list of imports at the top of Module EnvironmentEvents.

    Remove any unwanted items and add the following code to the EnvironmentEvents module

    Public Sub DebuggerEvents_OnEnterDesignMode(ByVal Reason As EnvDTE.dbgEventReason) Handles DebuggerEvents.OnEnterDesignMode
    Systray.Cleanup()
    MsgBox("Entered design mode!")
    End Sub
    
  5. If it works remove MsgBox("Entered design mode!") because it's annoying to have a message box popping up every time you return from a debugging session.

Upvotes: 2

Ian
Ian

Reputation: 111

You can kill the icon using the parent Window's Closed event. This works in my WPF app, even when testing in Visual Studio (2010 in my case):

        parentWindow.Closing += (object sender, CancelEventArgs e) =>
        {
            notifyIcon.Visible = false;
            notifyIcon.Icon = null;
            notifyIcon.Dispose();
        };

Upvotes: 11

Richard Slater
Richard Slater

Reputation: 6368

Is this while you are debugging your application? if so this is because the messages that remove the icon from the system tray are only sent when the application exits normally, if it terminates because of an exception or because you terminate it from Visual Studio the icon will remain until you mouse over it.

Upvotes: 26

Related Questions