Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Visual Basic
  4. Remove pesky "zombie" icons from the Windows System Tray

Remove pesky "zombie" icons from the Windows System Tray

Scheduled Pinned Locked Moved Visual Basic
csharphelpc++winforms
5 Posts 2 Posters 22 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    Dan Desjardins
    wrote on last edited by
    #1

    There is no (apparent) API for managing icons in the system tray in Windows. Applications that live in the system tray that are aborted through Task Manager, or end without a proper shutdown (error out) will leave their icons in the system tray. Restarting the application then puts another icon in the tray. The zombie icons persist and the only official way to remove them is to float your mouse over them and POOF - they disappear. There simply is no Win32 API for clearing these out. In my research I have found that a lot of folks are looking for the ability to clear these out. I even found one commercial product from a company called APPSVOID But it's bundled in an expensive subscription package. I suspect the commercial product uses hacks that can be found in various places in languages other than VB. One such can be found at Refresh Notification Area This works, but is written entirely in C++. I'm not a C++ Programmer so I spent some time clumsily refactoring the C++ to vb.net (Framework 4.8 in a Winforms application) and came up with the following and would love it if someone smarter than me could look over my shoulder, laugh a little, and help out:

    Imports System.Runtime.InteropServices

    Public Class ClearSystemTray

    Private Const WM\_MOUSEMOVE As UInteger = &H200
    
    Private Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
    End Function
    
    '
    'Private Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    'End Function
    
    Public Shared Function FindWindowW( ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    End Function
    
    Private Shared Function FindWindowEx(ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal lclassName As String, ByVal windowTitle As String) As IntPtr
    End Function
    
    Private Shared Function GetClientRect(ByVal hWnd As System.IntPtr,
    
    Richard DeemingR 1 Reply Last reply
    0
    • D Dan Desjardins

      There is no (apparent) API for managing icons in the system tray in Windows. Applications that live in the system tray that are aborted through Task Manager, or end without a proper shutdown (error out) will leave their icons in the system tray. Restarting the application then puts another icon in the tray. The zombie icons persist and the only official way to remove them is to float your mouse over them and POOF - they disappear. There simply is no Win32 API for clearing these out. In my research I have found that a lot of folks are looking for the ability to clear these out. I even found one commercial product from a company called APPSVOID But it's bundled in an expensive subscription package. I suspect the commercial product uses hacks that can be found in various places in languages other than VB. One such can be found at Refresh Notification Area This works, but is written entirely in C++. I'm not a C++ Programmer so I spent some time clumsily refactoring the C++ to vb.net (Framework 4.8 in a Winforms application) and came up with the following and would love it if someone smarter than me could look over my shoulder, laugh a little, and help out:

      Imports System.Runtime.InteropServices

      Public Class ClearSystemTray

      Private Const WM\_MOUSEMOVE As UInteger = &H200
      
      Private Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
      End Function
      
      '
      'Private Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
      'End Function
      
      Public Shared Function FindWindowW( ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
      End Function
      
      Private Shared Function FindWindowEx(ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal lclassName As String, ByVal windowTitle As String) As IntPtr
      End Function
      
      Private Shared Function GetClientRect(ByVal hWnd As System.IntPtr,
      
      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #2

      The obvious "dumb thing" was linking to the expensive commercial application, which is technically spam. :) Also, returning Task(Of Task) is unnecessary; just have the function return Task, and remove the Return Task.CompletedTask lines. And calling Application.DoEvents is a code-smell. Aside from the fact that it ties your code to WinForms, it will also lead to unexpected behaviour.


      "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      D 1 Reply Last reply
      0
      • Richard DeemingR Richard Deeming

        The obvious "dumb thing" was linking to the expensive commercial application, which is technically spam. :) Also, returning Task(Of Task) is unnecessary; just have the function return Task, and remove the Return Task.CompletedTask lines. And calling Application.DoEvents is a code-smell. Aside from the fact that it ties your code to WinForms, it will also lead to unexpected behaviour.


        "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

        D Offline
        D Offline
        Dan Desjardins
        wrote on last edited by
        #3

        Thanks - yes - you are right. I will see if I can edit the link away. If people are interested they can google it themselves! The Application.DoEvents are not in my final version - I should have removed them before I posted. I often use those to host a breakpoint for convenient place to examine values. Yes - I do occasionally leave them accidentally so I would agree, that remains in the dumb category. However, I do find the occasional DoEvents necessary in some synchronously running tight loops. I thought an async function should always return a value and some examples from which I learned a long time ago have that task(of task) with the return of task.completedtask. Wow - that is all over my code...

        Richard DeemingR 1 Reply Last reply
        0
        • D Dan Desjardins

          Thanks - yes - you are right. I will see if I can edit the link away. If people are interested they can google it themselves! The Application.DoEvents are not in my final version - I should have removed them before I posted. I often use those to host a breakpoint for convenient place to examine values. Yes - I do occasionally leave them accidentally so I would agree, that remains in the dumb category. However, I do find the occasional DoEvents necessary in some synchronously running tight loops. I thought an async function should always return a value and some examples from which I learned a long time ago have that task(of task) with the return of task.completedtask. Wow - that is all over my code...

          Richard DeemingR Offline
          Richard DeemingR Offline
          Richard Deeming
          wrote on last edited by
          #4

          Dan Desjardins wrote:

          I thought an async function should always return a value

          Perhaps you were confused by the valid "avoid async void" warning - in VB.NET, that would be the equivalent of an Async Sub: Avoid async void methods | You’ve Been Haacked[^] An Async Function that returns a non-generic Task is similar to a synchronous Sub that doesn't return anything. An Async Function that returns Task(Of Foo) is similar to a synchronous Function that returns Foo. In other words:

          Sub PrintSync()
          ...
          End Sub

          PrintSync()

          would become:

          Async Function PrintAsync() As Task
          ...
          End Function

          Await PrintAsync()

          And:

          Function CalculateSync() As Integer
          ...
          Return 42
          End Function

          Dim i As Integer = CalculateSync()

          would become:

          Async Function CalculateAsync() As Task(Of Integer)
          ...
          Return 42
          End Function

          Dim i As Integer = Await CalculateAsync()


          "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

          "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

          D 1 Reply Last reply
          0
          • Richard DeemingR Richard Deeming

            Dan Desjardins wrote:

            I thought an async function should always return a value

            Perhaps you were confused by the valid "avoid async void" warning - in VB.NET, that would be the equivalent of an Async Sub: Avoid async void methods | You’ve Been Haacked[^] An Async Function that returns a non-generic Task is similar to a synchronous Sub that doesn't return anything. An Async Function that returns Task(Of Foo) is similar to a synchronous Function that returns Foo. In other words:

            Sub PrintSync()
            ...
            End Sub

            PrintSync()

            would become:

            Async Function PrintAsync() As Task
            ...
            End Function

            Await PrintAsync()

            And:

            Function CalculateSync() As Integer
            ...
            Return 42
            End Function

            Dim i As Integer = CalculateSync()

            would become:

            Async Function CalculateAsync() As Task(Of Integer)
            ...
            Return 42
            End Function

            Dim i As Integer = Await CalculateAsync()


            "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

            D Offline
            D Offline
            Dan Desjardins
            wrote on last edited by
            #5

            And now that makes sense to me - especially since your return int is 42 :cool:

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups