/// <summary>
        /// Removes the given tray icon using the TrayData we've fetched for it.
        /// </summary>
        private static void RemoveIcon(ExtraButtonData td)
        {
            var data = new NotifyIconData()
            {
                hWnd = td.hWnd,
                uID  = td.uID
            };

            //Try to remove the icon. Throw the last Win32 error if this fails.
            if (!Shell_NotifyIcon(NIM_DELETE, data))
            {
                throw new Win32Exception();
            }
        }
        /// <summary>
        /// Removes any zombie icons (those whose processes no longer exist) from the notification tray.
        /// </summary>
        /// <returns>The number of tray icons removed.</returns>
        public static uint RemoveZombieIcons()
        {
            var  toolbarButton     = new ToolbarButton();
            var  extraData         = new ExtraButtonData();
            uint totalRemovedCount = 0;
            uint totalItemCount    = 0;

            foreach (var windowList in TrayWindowSearchList)
            {
                //Get a handle to the toolbar window
                IntPtr toolbarHandle = FindNestedWindow(windowList);
                if (toolbarHandle == IntPtr.Zero)
                {
                    Utilities.Log($"No window found for list: {windowList}");
                    continue;
                }

                //Use that handle to open the toolbar's process
                using (LP_Process process = new LP_Process(toolbarHandle))
                {
                    //Allocate shared memory in the process to store toolbar button data for us to read
                    IntPtr remoteButtonPtr = process.Allocate(toolbarButton);
                    process.Allocate(extraData);

                    //Ask the window how many buttons it contains so we can iterate over them
                    uint itemCount = (uint)SendMessage(toolbarHandle, TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero);
                    totalItemCount += itemCount;
                    Utilities.Log($"Found {itemCount} tray icons (some may be hidden)");
                    uint removedCount = 0;
                    for (uint item = 0; item < itemCount; item++)
                    {
                        //We remove items starting from the leftmost (#0), so for each item we have removed, the remaining items' indices
                        // will have 1 subtracted from them (since they all just got shifted left by 1).
                        uint index = item - removedCount;

                        //Get info for this toolbar button
                        if ((uint)SendMessage(toolbarHandle, TB_GETBUTTON, new IntPtr(index), remoteButtonPtr) == 0)
                        {
                            throw new ApplicationException("TB_GETBUTTON failed");
                        }
                        process.Read(toolbarButton, remoteButtonPtr);
                        process.Read(extraData, toolbarButton.dwData);

                        //Open the handle for this button to see if its parent process exists or not. If it has no parent, it's a zombie - kill it!
                        IntPtr buttonHandle = extraData.hWnd;
                        if (buttonHandle == IntPtr.Zero)
                        {
                            throw new ApplicationException("Invalid handle in tray button data");
                        }
                        using (LP_Process proc = new LP_Process(buttonHandle))
                        {
                            if (proc.ownerProcessID == 0)
                            {
                                RemoveIcon(extraData);
                                removedCount++;
                                totalRemovedCount++;
                            }
                        }
                    }
                }
            }

            Utilities.Log($"Done. {totalItemCount} icons found, {totalRemovedCount} icons removed.");
            return(totalRemovedCount);
        }