CmdPal: Add hidden window as owner for tool windows#42902
Conversation
Switches to a more reliable method for hiding tool windows from the taskbar and Alt+Tab. Previously, this was done by adding WS_EX_TOOLWINDOW to an unowned top-level window, which proved unreliable in multiple scenarios. This change uses a hidden owner window instead.
There was a problem hiding this comment.
Pull Request Overview
This PR refactors the window taskbar and Alt+Tab visibility management into a new reusable HiddenOwnerWindowBehavior class. The refactoring consolidates duplicated logic from MainWindow and ToastWindow that previously used extended window styles directly.
- Introduces
HiddenOwnerWindowBehaviorto centralize taskbar/Alt+Tab visibility logic using a hidden owner window pattern - Removes
ApplyWindowStyle()fromMainWindowand simplifies initialization - Updates
ToastWindowto use the new behavior class instead of direct style manipulation
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/modules/cmdpal/Microsoft.CmdPal.UI/HiddenOwnerWindowBehavior.cs | New class that encapsulates taskbar visibility logic using hidden owner window pattern and extended window styles |
| src/modules/cmdpal/Microsoft.CmdPal.UI/MainWindow.xaml.cs | Replaced ApplyWindowStyle() method with HiddenOwnerWindowBehavior instance; added early HideWindow() call |
| src/modules/cmdpal/Microsoft.CmdPal.UI/ToastWindow.xaml.cs | Removed direct window style manipulation and replaced with HiddenOwnerWindowBehavior |
| src/modules/cmdpal/Microsoft.CmdPal.UI/Helpers/WindowExtensions.cs | Changed GetWindowHwnd() visibility from private to public to support the new behavior class |
| src/modules/cmdpal/Microsoft.CmdPal.UI/NativeMethods.txt | Added P/Invoke entries for new window creation APIs |
| HideWindow(); | ||
|
|
||
| _hwnd = new HWND(WinRT.Interop.WindowNative.GetWindowHandle(this).ToInt32()); |
There was a problem hiding this comment.
HideWindow() is called before _hwnd is initialized on line 71. The HideWindow() method calls Cloak(), which uses _hwnd (lines 385, 398). This will cause _hwnd to have its default uninitialized value when used, potentially leading to incorrect behavior or a crash. Move this call to after line 71 where _hwnd is initialized, or move the _hwnd initialization before this call.
| HideWindow(); | |
| _hwnd = new HWND(WinRT.Interop.WindowNative.GetWindowHandle(this).ToInt32()); | |
| _hwnd = new HWND(WinRT.Interop.WindowNative.GetWindowHandle(this).ToInt32()); | |
| HideWindow(); |
| private HWND EnsureHiddenOwner() | ||
| { | ||
| if (_hiddenOwnerHwnd.IsNull) | ||
| { | ||
| _hiddenWindow = new Window(); | ||
| _hiddenOwnerHwnd = _hiddenWindow.GetWindowHwnd(); | ||
| } | ||
|
|
||
| return _hiddenOwnerHwnd; | ||
| } |
There was a problem hiding this comment.
The hidden owner window (_hiddenWindow) is created in EnsureHiddenOwner() but is never disposed. This can lead to a resource leak. Consider implementing IDisposable on this class and disposing of _hiddenWindow (e.g., by calling _hiddenWindow?.Close()) in the Dispose method. The owning classes (MainWindow and ToastWindow) should then call Dispose on their HiddenOwnerWindowBehavior instances when they are disposed or closed.
| GetStockObject | ||
| GetModuleHandle No newline at end of file |
There was a problem hiding this comment.
GetModuleHandle is listed twice in this file (lines 58 and 66). Remove the duplicate entry on line 66.
| GetStockObject | |
| GetModuleHandle | |
| GetStockObject |
## Summary of the Pull Request This PR changes the method used to hide tool windows from the taskbar and Alt+Tab to a more reliable approach. Previously, this was achieved by adding `WS_EX_TOOLWINDOW` to an unowned top-level window, which proved unreliable in several scenarios. The new implementation assigns a hidden window as the owner of each tool window. This ensures that the window does not appear on the taskbar even when the Windows setting **Settings → System → Multitasking → On the taskbar, show all opened windows** is set to **On all desktops**. ## Change log one-liner Fixes Command Palette windows occasionally appearing on the taskbar under certain system settings. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #42395 - [x] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [x] **Localization:** All end-user-facing strings can be localized - [x] **Dev docs:** Added/updated - [x] **New binaries:** none - [x] **Documentation updated:** no need <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Tested alongside the stable CmdPal on a system with

Summary of the Pull Request
This PR changes the method used to hide tool windows from the taskbar and Alt+Tab to a more reliable approach.
Previously, this was achieved by adding
WS_EX_TOOLWINDOWto an unowned top-level window, which proved unreliable in several scenarios.The new implementation assigns a hidden window as the owner of each tool window.
This ensures that the window does not appear on the taskbar even when the Windows setting
Settings → System → Multitasking → On the taskbar, show all opened windows is set to On all desktops.
Change log one-liner
Fixes Command Palette windows occasionally appearing on the taskbar under certain system settings.
PR Checklist
Detailed Description of the Pull Request / Additional comments
Validation Steps Performed
Tested alongside the stable CmdPal on a system with