Ensure Command Palette main window remains hidden on taskbar Windows Explorer restarts (#40406)

## Summary of the Pull Request

Ensures the Command Palette main window stays hidden from the taskbar
after Windows Explorer restarts. Also updates how app switcher
visibility is managed to prevent unhandled exceptions and avoid startup
crashes when Explorer is not running or is not responsive.

## PR Checklist

- [x] Closes: #40334
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** no tests
- [x] **Localization:** nothing to localize
- [x] **Dev docs:** nothing to update
- [x] **New binaries:** no new binaries
- [x] **Documentation updated:** nothing to update

## Detailed Description of the Pull Request / Additional comments
- Settings on the main window are reapplied after the taskbar is
re-created (e.g., after Windows Explorer restarts), restoring visibility
settings for the app switcher and taskbar button.
- Defensive handling of the property AppWindow.IsShownInSwitchers
controlling appearance in system representations such as ALT+TAB and the
taskbar, to avoid errors when Windows Explorer is not running (see
https://github.com/microsoft/microsoft-ui-xaml/issues/8596).
- Prevents application startup failures when the Command Palette is
launched in environments without Windows Explorer.

## Validation Steps Performed
- Verified that the CmdPal main window taskbar button is not visible
after Explorer is restarted (without an attached debugger).
- Verified that CmdPal can be started when Explorer is not running.
- Verified that the CmdPal main window taskbar button is visible after
Explorer is restarted (if a debugger is attached to CmdPal).
This commit is contained in:
Jiří Polášek
2025-07-09 19:35:42 +02:00
committed by GitHub
parent 802bc3bd34
commit 09c1575fa0
3 changed files with 31 additions and 4 deletions

View File

@@ -17,4 +17,19 @@ public static class WindowExtensions
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon(@"Assets\icon.ico");
}
public static void SetVisibilityInSwitchers(this Window window, bool showInSwitchers)
{
try
{
// IsShownInSwitchers needs to change the value to apply the effect, but its state might be out-of-sync with
// the actual state of the switchers, so we need to toggle it.
window.AppWindow.IsShownInSwitchers = !showInSwitchers;
window.AppWindow.IsShownInSwitchers = showInSwitchers;
}
catch (NotImplementedException)
{
// SetShownInSwitchers failed. This can happen if the Explorer is not running.
}
}
}

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.Runtime.InteropServices;
using CmdPalKeyboardService;
using CommunityToolkit.Mvvm.Messaging;
@@ -42,6 +43,9 @@ public sealed partial class MainWindow : WindowEx,
IRecipient<HideWindowMessage>,
IRecipient<QuitMessage>
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Stylistically, window messages are WM_")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1306:Field names should begin with lower-case letter", Justification = "Stylistically, window messages are WM_")]
private readonly uint WM_TASKBAR_RESTART;
private readonly HWND _hwnd;
private readonly WNDPROC? _hotkeyWndProc;
private readonly WNDPROC? _originalWndProc;
@@ -87,6 +91,8 @@ public sealed partial class MainWindow : WindowEx,
SizeChanged += WindowSizeChanged;
RootShellPage.Loaded += RootShellPage_Loaded;
WM_TASKBAR_RESTART = PInvoke.RegisterWindowMessage("TaskbarCreated");
// LOAD BEARING: If you don't stick the pointer to HotKeyPrc into a
// member (and instead like, use a local), then the pointer we marshal
// into the WindowLongPtr will be useless after we leave this function,
@@ -147,9 +153,7 @@ public sealed partial class MainWindow : WindowEx,
_ignoreHotKeyWhenFullScreen = settings.IgnoreShortcutWhenFullscreen;
// This will prevent our window from appearing in alt+tab or the taskbar.
// You'll _need_ to use the hotkey to summon it.
AppWindow.IsShownInSwitchers = System.Diagnostics.Debugger.IsAttached;
this.SetVisibilityInSwitchers(Debugger.IsAttached);
}
// We want to use DesktopAcrylicKind.Thin and custom colors as this is the default material
@@ -600,6 +604,14 @@ public sealed partial class MainWindow : WindowEx,
return (LRESULT)IntPtr.Zero;
}
default:
if (uMsg == WM_TASKBAR_RESTART)
{
HotReloadSettings();
}
break;
}
return PInvoke.CallWindowProc(_originalWndProc, hwnd, uMsg, wParam, lParam);

View File

@@ -35,7 +35,7 @@ public sealed partial class ToastWindow : WindowEx,
{
this.InitializeComponent();
AppWindow.Hide();
AppWindow.IsShownInSwitchers = false;
this.SetVisibilityInSwitchers(false);
ExtendsContentIntoTitleBar = true;
AppWindow.SetPresenter(AppWindowPresenterKind.CompactOverlay);
this.SetIcon();