using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Vanara.Extensions; using Vanara.InteropServices; using Vanara.PInvoke; using static Vanara.PInvoke.ComCtl32; using static Vanara.PInvoke.Shell32; using static Vanara.PInvoke.User32; namespace Vanara.Windows.Shell.TaskBar { /// Provides information about and some control of the system taskbar. public static class Taskbar { private const string NotifyWndClass = "TrayNotifyWnd"; private const string PagerWndClass = "SysPager"; private const string TaskbarWndClass = "Shell_TrayWnd"; private const string ToolbarWndClass = "ToolbarWindow32"; private static readonly Lazy isMinWin7 = new(() => PInvokeClientExtensions.IsPlatformSupported(PInvokeClient.Windows7)); private static bool autoHide, alwaysTop; private static ABE edge; private static HWND hwnd; private static RECT rect; /// /// Gets or sets a value indicating whether the taskbar is always on top. This value is always true for systems since Windows 7. /// /// if always on top; otherwise, . public static bool AlwaysOnTop { get { GetState(); return alwaysTop; } set { if (!isMinWin7.Value) { GetState(); if (alwaysTop != value) { alwaysTop = value; SetState(); } } else throw new PlatformNotSupportedException(); } } /// Gets or sets a value indicating whether the taskbar is configured to automatically hide itself when not used. /// if automatically hidden; otherwise, . public static bool AutoHide { get { GetState(); return autoHide; } set { GetState(); if (autoHide != value) { autoHide = value; SetState(); } } } /// Gets the bounds of the taskbar. /// The bounds. public static RECT Bounds { get { GetPos(); return rect; } //set { GetPos(); if (rect != value) { rect = value; SetPos(); } } } /// Gets a value that determines on which edge of the screen the taskbar is displayed. /// The screen edge. public static ABE Edge { get { GetPos(); return edge; } //set { GetPos(); if (edge != value) { edge = value; SetPos(); } } } /// Gets the window handle of the System Taskbar. /// The window handle. public static HWND Handle { get { GetPos(); return hwnd; } } /// Gets the tray icons. /// The tray icons. public static IEnumerable TrayIcons { get { const TBIF bif = TBIF.TBIF_BYINDEX | TBIF.TBIF_COMMAND | TBIF.TBIF_SIZE | TBIF.TBIF_STATE | TBIF.TBIF_STYLE | TBIF.TBIF_TEXT; var hwnd = GetTrayWindow(); if (hwnd.IsNull) yield break; using SafeCoTaskMemString strBuf = new(512); TBBUTTONINFO defBI = new() { cbSize = (uint)Marshal.SizeOf(typeof(TBBUTTONINFO)), dwMask = bif, pszText = strBuf, cchText = strBuf.Capacity }; var cnt = SendMessage(hwnd, ToolbarMessage.TB_BUTTONCOUNT).ToInt32(); var badRes = new IntPtr(-1); for (int i = 0; i < cnt; i++) { TBBUTTONINFO btnInf = defBI; btnInf.cchText = strBuf.Capacity; strBuf[0] = '\0'; Win32Error.ThrowLastErrorIf(SendMessage(hwnd, ToolbarMessage.TB_GETBUTTONINFOW, (IntPtr)i, ref btnInf), p => p == badRes); yield return new(btnInf); } } } /// Broadcasts the "TaskbarCreated" message to all windows. This is generally used to refresh the taskbar icons. public static void BroadcastTaskbarCreated() { var msg = Win32Error.ThrowLastErrorIf(RegisterWindowMessage("TaskbarCreated"), i => i == 0); Win32Error.ThrowLastErrorIfFalse(SendNotifyMessage(HWND.HWND_BROADCAST, msg)); } private static void GetPos() { APPBARDATA abd = new(default); Win32Error.ThrowLastErrorIf(SHAppBarMessage(ABM.ABM_GETTASKBARPOS, ref abd), r => r == IntPtr.Zero); rect = abd.rc; edge = abd.uEdge; hwnd = abd.hWnd == default ? User32.FindWindowEx(default, default, TaskbarWndClass, null) : abd.hWnd; } private static void GetState() { APPBARDATA abd = new(default); ABS state = (ABS)SHAppBarMessage(ABM.ABM_GETSTATE, ref abd).ToInt32(); autoHide = state.IsFlagSet(ABS.ABS_AUTOHIDE); alwaysTop = isMinWin7.Value || state.IsFlagSet(ABS.ABS_ALWAYSONTOP); } private static HWND GetTrayWindow() { HWND hwnd = FindWindow(TaskbarWndClass, ""); if (!hwnd.IsNull) { hwnd = FindWindowEx(hwnd, default, NotifyWndClass, ""); if (!hwnd.IsNull) { hwnd = FindWindowEx(hwnd, default, PagerWndClass, ""); if (!hwnd.IsNull) { return FindWindowEx(hwnd, default, ToolbarWndClass, null); } } } return hwnd; } private static void SetPos() { APPBARDATA abd = new(hwnd, 0, edge, rect); SHAppBarMessage(ABM.ABM_SETPOS, ref abd); } private static void SetState() { if (hwnd == default) { GetPos(); } APPBARDATA abd = new(hwnd, lParam: (int)((autoHide ? ABS.ABS_AUTOHIDE : 0) | (alwaysTop ? ABS.ABS_ALWAYSONTOP : 0))); SHAppBarMessage(ABM.ABM_SETSTATE, ref abd); } } /// public class TrayIcon { internal TrayIcon(in TBBUTTONINFO inf) { CommandId = inf.idCommand; ImageIdx = inf.iImage; State = inf.fsState; Style = inf.fsStyle; Width = inf.cx; Text = StringHelper.GetString(inf.pszText, CharSet.Unicode, inf.cchText); } /// Command identifier of the button. public int CommandId { get; } /// Image index of the button. public int ImageIdx { get; } /// State flags of the button. This can be one or more of the values listed in Toolbar Button States. public TBSTATE State { get; } /// Style flags of the button. This can be one or more of the values listed in Toolbar Control and Button Styles. public ToolbarStyle Style { get; } /// Address of a character buffer that contains or receives the button text. public string Text { get; } /// Width of the button, in pixels. public ushort Width { get; } } }