private static void RedrawWindowsSystemTrayArea() { try { // Windows XP and earlier var hNotificationArea = Native.FindWindowEx ( Native.FW(Native.FW(Native.FW(IntPtr.Zero, "Shell_TrayWnd"), "TrayNotifyWnd"), "SysPager"), IntPtr.Zero, "ToolbarWindow32", "Notification Area" ); // Windows Vista and later if (hNotificationArea == IntPtr.Zero || hNotificationArea.ToInt32() == Native.INVALID_HANDLE_VALUE) { hNotificationArea = Native.FindWindowEx ( Native.FW(Native.FW(Native.FW(IntPtr.Zero, "Shell_TrayWnd"), "TrayNotifyWnd"), "SysPager"), IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area" ); } if (hNotificationArea == IntPtr.Zero || hNotificationArea.ToInt32() == Native.INVALID_HANDLE_VALUE) { return; } // Get the notification bounds var rect = new Native.Rect(); Native.GetClientRect(hNotificationArea, ref rect); // Wiggle the mouse over the notification area // Note: this doesn't actually move the mouse cursor on the screen -- this just sends a message to the system tray window // that mouse movement occurred over it, forcing it to refresh. Sending messages asking for a repaint or invalidated // area don't work, but this does. for (uint x = 0; x < rect.Right; x += 5) { for (uint y = 0; y < rect.Bottom; y += 5) { Native.SendMessage(hNotificationArea, Native.WM_MOUSEMOVE, 0, (y << 16) | x); } } } catch { // ignored } }
public static void ToggleWindowsTaskbarVisibility(Boolstate forced = Boolstate.Indeterminate) { try { var hTaskBar = Native.FindWindow("Shell_TrayWnd", null); if (hTaskBar.ToInt32() == Native.INVALID_HANDLE_VALUE || hTaskBar == IntPtr.Zero) { return; } var TaskBarIsCurrentlyVisible = Native.IsWindowVisible(hTaskBar); var wantToMakeWindowsTaskbarVisible = forced == Boolstate.True ? true : forced == Boolstate.False ? false : !TaskBarIsCurrentlyVisible; // For forced modes, if the taskbar is already visible and we're requesting to show it, then do nothing if (wantToMakeWindowsTaskbarVisible && TaskBarIsCurrentlyVisible) { return; } // For forced modes, if the taskbar is already hidden and we're requesting to hide it, then do nothing if (!wantToMakeWindowsTaskbarVisible && !TaskBarIsCurrentlyVisible) { return; } // If we're hiding the taskbar, let's take some notes on the original screen desktop work areas if (!wantToMakeWindowsTaskbarVisible) { foreach (var screen in Screen.AllScreens) { var osi = new OriginalScreenInfo(); osi.Screen = screen; osi.Workarea = new Native.Rect(); osi.Workarea.Left = screen.WorkingArea.Left; osi.Workarea.Top = screen.WorkingArea.Top; osi.Workarea.Right = screen.WorkingArea.Right; osi.Workarea.Bottom = screen.WorkingArea.Bottom; OriginalScreens.Add(osi); } } // Show or hide the Windows taskbar Native.ShowWindow(hTaskBar, wantToMakeWindowsTaskbarVisible ? WindowShowStyle.ShowNoActivate : WindowShowStyle.Hide); // Keep track of the taskbar state so we don't let the user accidentally close Borderless Gaming WindowsTaskbarIsHidden = !wantToMakeWindowsTaskbarVisible; if (wantToMakeWindowsTaskbarVisible) { // If we're showing the taskbar, let's restore the original screen desktop work areas... foreach (var osi in OriginalScreens) { Native.SystemParametersInfo(SPI.SPI_SETWORKAREA, 0, ref osi.Workarea, SPIF.SPIF_SENDCHANGE); } // ...and then forget them (we don't need them anymore) OriginalScreens.Clear(); // And we need to redraw the system tray in case tray icons from other applications did something while the // taskbar was hidden. Simulating mouse movement over the system tray seems to be the best way to get this // done. RedrawWindowsSystemTrayArea(); } else { // If we're hiding the taskbar, let's set the screen desktop work area over the entire screen so that // maximizing windows works as expected. foreach (var osi in OriginalScreens) { var rect = new Native.Rect(); rect.Left = osi.Screen.Bounds.Left; rect.Top = osi.Screen.Bounds.Top; rect.Right = osi.Screen.Bounds.Right; rect.Bottom = osi.Screen.Bounds.Bottom; Native.SystemParametersInfo(SPI.SPI_SETWORKAREA, 0, ref rect, SPIF.SPIF_SENDCHANGE); // Note: WinAPI SystemParametersInfo() will automatically determine which screen by the rectangle we pass in. // (it's not possible to specify which screen we're referring to directly) } } } catch { } }