CmdPal: Remove dead code from Window Walker and cleanup (#45570)

## Summary of the Pull Request

This PR is a light cleanup on Window Walker built-in extension:

- Removes unused types
- Removes redundant code
- Fixes inconsistent naming conventions
- De-LINQ-ify
- Fixes XML doc
- Updates language constructs to the latest (use of
System.Threading.Lock, Collection expressions)
- Updates types and members visibility and makes static classes static

⚠️ Trickiest part are 44ac1c1 and 26c946c that removes redundant null
checks.
This commit is contained in:
Jiří Polášek
2026-02-24 13:29:58 +01:00
committed by GitHub
parent 4f5837d4e9
commit 07b8915e19
25 changed files with 169 additions and 513 deletions

View File

@@ -2,15 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Components; using Microsoft.CmdPal.Ext.WindowWalker.Components;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands; namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
@@ -29,7 +22,7 @@ internal sealed partial class CloseWindowCommand : InvokableCommand
{ {
if (!_window.IsWindow) if (!_window.IsWindow)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"Cannot close the window '{_window.Title}' ({_window.Hwnd}), because it doesn't exist." }); ExtensionHost.LogMessage(new LogMessage { Message = $"Cannot close the window '{_window.Title}' ({_window.Hwnd}), because it doesn't exist." });
} }
_window.CloseThisWindow(); _window.CloseThisWindow();

View File

@@ -2,16 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Components; using Microsoft.CmdPal.Ext.WindowWalker.Components;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands; namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
@@ -36,7 +28,7 @@ internal sealed partial class EndTaskCommand : InvokableCommand
// Validate process // Validate process
if (!window.IsWindow || !window.Process.DoesExist || string.IsNullOrEmpty(window.Process.Name) || !window.Process.Name.Equals(WindowProcess.GetProcessNameFromProcessID(window.Process.ProcessID), StringComparison.Ordinal)) if (!window.IsWindow || !window.Process.DoesExist || string.IsNullOrEmpty(window.Process.Name) || !window.Process.Name.Equals(WindowProcess.GetProcessNameFromProcessID(window.Process.ProcessID), StringComparison.Ordinal))
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"Cannot kill process '{window.Process.Name}' ({window.Process.ProcessID}) of the window '{window.Title}' ({window.Hwnd}), because it doesn't exist." }); ExtensionHost.LogMessage(new LogMessage { Message = $"Cannot kill process '{window.Process.Name}' ({window.Process.ProcessID}) of the window '{window.Title}' ({window.Hwnd}), because it doesn't exist." });
// TODO GH #86 -- need to figure out how to show status message once implemented on host // TODO GH #86 -- need to figure out how to show status message once implemented on host
return false; return false;

View File

@@ -2,26 +2,14 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Components;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands; namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
internal sealed partial class ExplorerInfoResultCommand : InvokableCommand internal sealed partial class ExplorerInfoResultCommand : InvokableCommand
{ {
public ExplorerInfoResultCommand()
{
}
public static bool OpenInShell(string path, string? arguments = null, string? workingDir = null, ShellRunAsType runAs = ShellRunAsType.None, bool runWithHiddenWindow = false) public static bool OpenInShell(string path, string? arguments = null, string? workingDir = null, ShellRunAsType runAs = ShellRunAsType.None, bool runWithHiddenWindow = false)
{ {
using var process = new Process(); using var process = new Process();
@@ -47,7 +35,7 @@ internal sealed partial class ExplorerInfoResultCommand : InvokableCommand
} }
catch (Win32Exception ex) catch (Win32Exception ex)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"Unable to open {path}: {ex.Message}" }); ExtensionHost.LogMessage(new LogMessage { Message = $"Unable to open {path}: {ex.Message}" });
return false; return false;
} }
} }

View File

@@ -2,15 +2,10 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.IO; using System.IO;
using Microsoft.CmdPal.Ext.WindowWalker.Components; using Microsoft.CmdPal.Ext.WindowWalker.Components;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Storage.Streams; using Windows.Storage.Streams;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands; namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
@@ -58,16 +53,13 @@ internal sealed partial class SwitchToWindowCommand : InvokableCommand
else else
{ {
var p = Process.GetProcessById((int)_window.Process.ProcessID); var p = Process.GetProcessById((int)_window.Process.ProcessID);
if (p is not null) try
{
var processFileName = p.MainModule?.FileName;
Icon = new IconInfo(processFileName);
}
catch
{ {
try
{
var processFileName = p.MainModule?.FileName;
Icon = new IconInfo(processFileName);
}
catch
{
}
} }
} }
} }
@@ -77,7 +69,7 @@ internal sealed partial class SwitchToWindowCommand : InvokableCommand
{ {
if (_window is null) if (_window is null)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = "Cannot switch to the window, because it doesn't exist." }); ExtensionHost.LogMessage(new LogMessage { Message = "Cannot switch to the window, because it doesn't exist." });
return CommandResult.Dismiss(); return CommandResult.Dismiss();
} }

View File

@@ -2,29 +2,29 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using Microsoft.CmdPal.Ext.WindowWalker.Commands; using Microsoft.CmdPal.Ext.WindowWalker.Commands;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers; using Microsoft.CmdPal.Ext.WindowWalker.Pages;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.System; using Windows.System;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components; namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
internal sealed class ContextMenuHelper internal static class ContextMenuHelper
{ {
internal static List<CommandContextItem> GetContextMenuResults(in WindowWalkerListItem listItem) internal static List<CommandContextItem> GetContextMenuResults(in WindowWalkerListItem listItem)
{ {
if (listItem?.Window is not Window windowData) ArgumentNullException.ThrowIfNull(listItem);
if (listItem.Window is null)
{ {
return []; return [];
} }
var contextMenu = new List<CommandContextItem>() var windowData = listItem.Window;
var contextMenu = new List<CommandContextItem>
{ {
new(new CloseWindowCommand(windowData)) new(new CloseWindowCommand(windowData))
{ {
RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.F4, 0), RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.F4),
}, },
}; };
@@ -35,7 +35,7 @@ internal sealed class ContextMenuHelper
{ {
contextMenu.Add(new CommandContextItem(new EndTaskCommand(windowData)) contextMenu.Add(new CommandContextItem(new EndTaskCommand(windowData))
{ {
RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.Delete, 0), RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.Delete),
IsCritical = true, IsCritical = true,
}); });
} }

View File

@@ -3,15 +3,12 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
// Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/ // Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components; namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
/// <summary> /// <summary>
/// Class containing methods to control the live preview /// Class containing methods to control the live preview
/// </summary> /// </summary>
internal sealed class LivePreview internal static class LivePreview
{ {
/// <summary> /// <summary>
/// Makes sure that a window is excluded from the live preview /// Makes sure that a window is excluded from the live preview

View File

@@ -3,12 +3,9 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
// Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/ // Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components; namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
@@ -20,27 +17,27 @@ internal sealed class OpenWindows
/// <summary> /// <summary>
/// Used to enforce single execution of EnumWindows /// Used to enforce single execution of EnumWindows
/// </summary> /// </summary>
private static readonly object _enumWindowsLock = new(); private static readonly Lock EnumWindowsLock = new();
/// <summary> /// <summary>
/// PowerLauncher main executable /// PowerLauncher main executable
/// </summary> /// </summary>
private static readonly string? _powerLauncherExe = Path.GetFileName(Environment.ProcessPath); private static readonly string? PowerLauncherExe = Path.GetFileName(Environment.ProcessPath);
/// <summary> /// <summary>
/// List of all the open windows /// List of all the open windows
/// </summary> /// </summary>
private readonly List<Window> windows = new(); private readonly List<Window> _windows = [];
/// <summary> /// <summary>
/// An instance of the class OpenWindows /// An instance of the class OpenWindows
/// </summary> /// </summary>
private static OpenWindows? instance; private static OpenWindows? _instance;
/// <summary> /// <summary>
/// Gets the list of all open windows /// Gets the list of all open windows
/// </summary> /// </summary>
internal List<Window> Windows => new(windows); internal List<Window> Windows => [.._windows];
/// <summary> /// <summary>
/// Gets an instance property of this class that makes sure that /// Gets an instance property of this class that makes sure that
@@ -51,9 +48,9 @@ internal sealed class OpenWindows
{ {
get get
{ {
instance ??= new OpenWindows(); _instance ??= new OpenWindows();
return instance; return _instance;
} }
} }
@@ -75,10 +72,10 @@ internal sealed class OpenWindows
try try
{ {
var tokenHandleParam = GCHandle.ToIntPtr(tokenHandle); var tokenHandleParam = GCHandle.ToIntPtr(tokenHandle);
lock (_enumWindowsLock) lock (EnumWindowsLock)
{ {
windows.Clear(); _windows.Clear();
EnumWindowsProc callbackptr = new EnumWindowsProc(WindowEnumerationCallBack); var callbackptr = new EnumWindowsProc(WindowEnumerationCallBack);
_ = NativeMethods.EnumWindows(callbackptr, tokenHandleParam); _ = NativeMethods.EnumWindows(callbackptr, tokenHandleParam);
} }
} }
@@ -98,7 +95,7 @@ internal sealed class OpenWindows
/// <param name="lParam">Value being passed from the caller (we don't use this but might come in handy /// <param name="lParam">Value being passed from the caller (we don't use this but might come in handy
/// in the future</param> /// in the future</param>
/// <returns>true to make sure to continue enumeration</returns> /// <returns>true to make sure to continue enumeration</returns>
internal bool WindowEnumerationCallBack(IntPtr hwnd, IntPtr lParam) private bool WindowEnumerationCallBack(IntPtr hwnd, IntPtr lParam)
{ {
var tokenHandle = GCHandle.FromIntPtr(lParam); var tokenHandle = GCHandle.FromIntPtr(lParam);
var target = (CancellationToken?)tokenHandle.Target ?? CancellationToken.None; var target = (CancellationToken?)tokenHandle.Target ?? CancellationToken.None;
@@ -109,18 +106,18 @@ internal sealed class OpenWindows
return false; return false;
} }
Window newWindow = new Window(hwnd); var newWindow = new Window(hwnd);
if (newWindow.IsWindow && newWindow.Visible && newWindow.IsOwner && if (newWindow.IsWindow && newWindow.Visible && newWindow.IsOwner &&
(!newWindow.IsToolWindow || newWindow.IsAppWindow) && !newWindow.TaskListDeleted && (!newWindow.IsToolWindow || newWindow.IsAppWindow) && !newWindow.TaskListDeleted &&
(newWindow.Desktop.IsVisible || !SettingsManager.Instance.ResultsFromVisibleDesktopOnly || WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.GetDesktopCount() < 2) && (newWindow.Desktop.IsVisible || !SettingsManager.Instance.ResultsFromVisibleDesktopOnly || WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.GetDesktopCount() < 2) &&
newWindow.ClassName != "Windows.UI.Core.CoreWindow" && newWindow.Process.Name != _powerLauncherExe) newWindow.ClassName != "Windows.UI.Core.CoreWindow" && newWindow.Process.Name != PowerLauncherExe)
{ {
// To hide (not add) preloaded uwp app windows that are invisible to the user and other cloaked windows, we check the cloak state. (Issue #13637.) // To hide (not add) preloaded uwp app windows that are invisible to the user and other cloaked windows, we check the cloak state. (Issue #13637.)
// (If user asking to see cloaked uwp app windows again we can add an optional plugin setting in the future.) // (If user asking to see cloaked uwp app windows again we can add an optional plugin setting in the future.)
if (!newWindow.IsCloaked || newWindow.GetWindowCloakState() == Window.WindowCloakState.OtherDesktop) if (!newWindow.IsCloaked || newWindow.GetWindowCloakState() == Window.WindowCloakState.OtherDesktop)
{ {
windows.Add(newWindow); _windows.Add(newWindow);
} }
} }

View File

@@ -1,13 +1,10 @@
// Copyright (c) Microsoft Corporation // Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Commands; using Microsoft.CmdPal.Ext.WindowWalker.Commands;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers; using Microsoft.CmdPal.Ext.WindowWalker.Pages;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components; namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
@@ -34,10 +31,6 @@ internal static class ResultHelper
for (var i = 0; i < list.Count; i++) for (var i = 0; i < list.Count; i++)
{ {
var window = list[i].Item; var window = list[i].Item;
if (window?.Process is null)
{
continue;
}
if (string.Equals(window.Process.Name, "explorer.exe", StringComparison.OrdinalIgnoreCase) && window.Process.IsShellProcess) if (string.Equals(window.Process.Name, "explorer.exe", StringComparison.OrdinalIgnoreCase) && window.Process.IsShellProcess)
{ {

View File

@@ -3,15 +3,10 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
// Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/ // Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components; namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
@@ -20,26 +15,11 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
/// </summary> /// </summary>
internal sealed class Window internal sealed class Window
{ {
/// <summary>
/// The handle to the window
/// </summary>
private readonly IntPtr hwnd;
/// <summary> /// <summary>
/// A static cache for the process data of all known windows /// A static cache for the process data of all known windows
/// that we don't have to query the data every time /// that we don't have to query the data every time
/// </summary> /// </summary>
private static readonly Dictionary<IntPtr, WindowProcess> _handlesToProcessCache = new(); private static readonly Dictionary<IntPtr, WindowProcess> HandlesToProcessCache = new();
/// <summary>
/// An instance of <see cref="WindowProcess"/> that contains the process information for the window
/// </summary>
private readonly WindowProcess processInfo;
/// <summary>
/// An instance of <see cref="VDesktop"/> that contains the desktop information for the window
/// </summary>
private readonly VDesktop desktopInfo;
/// <summary> /// <summary>
/// Gets the title of the window (the string displayed at the top of the window) /// Gets the title of the window (the string displayed at the top of the window)
@@ -48,11 +28,11 @@ internal sealed class Window
{ {
get get
{ {
var sizeOfTitle = NativeMethods.GetWindowTextLength(hwnd); var sizeOfTitle = NativeMethods.GetWindowTextLength(Hwnd);
if (sizeOfTitle++ > 0) if (sizeOfTitle++ > 0)
{ {
StringBuilder titleBuffer = new StringBuilder(sizeOfTitle); var titleBuffer = new StringBuilder(sizeOfTitle);
var numCharactersWritten = NativeMethods.GetWindowText(hwnd, titleBuffer, sizeOfTitle); var numCharactersWritten = NativeMethods.GetWindowText(Hwnd, titleBuffer, sizeOfTitle);
if (numCharactersWritten == 0) if (numCharactersWritten == 0)
{ {
return string.Empty; return string.Empty;
@@ -70,17 +50,17 @@ internal sealed class Window
/// <summary> /// <summary>
/// Gets the handle to the window /// Gets the handle to the window
/// </summary> /// </summary>
internal IntPtr Hwnd => hwnd; internal IntPtr Hwnd { get; }
/// <summary> /// <summary>
/// Gets the object of with the process information of the window /// Gets the object of with the process information of the window
/// </summary> /// </summary>
internal WindowProcess Process => processInfo; internal WindowProcess Process { get; }
/// <summary> /// <summary>
/// Gets the object of with the desktop information of the window /// Gets the object of with the desktop information of the window
/// </summary> /// </summary>
internal VDesktop Desktop => desktopInfo; internal VDesktop Desktop { get; }
/// <summary> /// <summary>
/// Gets the name of the class for the window represented /// Gets the name of the class for the window represented
@@ -130,7 +110,7 @@ internal sealed class Window
/// <summary> /// <summary>
/// Gets a value indicating whether the window is minimized /// Gets a value indicating whether the window is minimized
/// </summary> /// </summary>
internal bool Minimized => GetWindowSizeState() == WindowSizeState.Minimized; private bool Minimized => GetWindowSizeState() == WindowSizeState.Minimized;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Window"/> class. /// Initializes a new instance of the <see cref="Window"/> class.
@@ -140,9 +120,9 @@ internal sealed class Window
internal Window(IntPtr hwnd) internal Window(IntPtr hwnd)
{ {
// TODO: Add verification as to whether the window handle is valid // TODO: Add verification as to whether the window handle is valid
this.hwnd = hwnd; Hwnd = hwnd;
processInfo = CreateWindowProcessInstance(hwnd); Process = CreateWindowProcessInstance(hwnd);
desktopInfo = WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.GetWindowDesktop(hwnd); Desktop = WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.GetWindowDesktop(hwnd);
} }
/// <summary> /// <summary>
@@ -155,7 +135,7 @@ internal sealed class Window
// to use ShowWindow for switching tabs in IE // to use ShowWindow for switching tabs in IE
// 2) SetForegroundWindow fails on minimized windows // 2) SetForegroundWindow fails on minimized windows
// Using Ordinal since this is internal // Using Ordinal since this is internal
if (processInfo.Name?.ToUpperInvariant().Equals("IEXPLORE.EXE", StringComparison.Ordinal) == true || !Minimized) if (Process.Name?.ToUpperInvariant().Equals("IEXPLORE.EXE", StringComparison.Ordinal) == true || !Minimized)
{ {
NativeMethods.SetForegroundWindow(Hwnd); NativeMethods.SetForegroundWindow(Hwnd);
} }
@@ -174,7 +154,7 @@ internal sealed class Window
/// <summary> /// <summary>
/// Helper function to close the window /// Helper function to close the window
/// </summary> /// </summary>
internal void CloseThisWindowHelper() private void CloseThisWindowHelper()
{ {
_ = NativeMethods.SendMessageTimeout(Hwnd, Win32Constants.WM_SYSCOMMAND, Win32Constants.SC_CLOSE, 0, 0x0000, 5000, out _); _ = NativeMethods.SendMessageTimeout(Hwnd, Win32Constants.WM_SYSCOMMAND, Win32Constants.SC_CLOSE, 0, 0x0000, 5000, out _);
} }
@@ -184,7 +164,7 @@ internal sealed class Window
/// </summary> /// </summary>
internal void CloseThisWindow() internal void CloseThisWindow()
{ {
Thread thread = new(new ThreadStart(CloseThisWindowHelper)); Thread thread = new(CloseThisWindowHelper);
thread.Start(); thread.Start();
} }
@@ -197,47 +177,47 @@ internal sealed class Window
{ {
icon = null; icon = null;
if (hwnd == IntPtr.Zero) if (Hwnd == IntPtr.Zero)
{ {
return false; return false;
} }
// Try WM_GETICON with SendMessageTimeout // Try WM_GETICON with SendMessageTimeout
if (NativeMethods.SendMessageTimeout(hwnd, Win32Constants.WM_GETICON, (UIntPtr)Win32Constants.ICON_BIG, IntPtr.Zero, Win32Constants.SMTO_ABORTIFHUNG, 100, out var result) != 0 && result != 0) if (NativeMethods.SendMessageTimeout(Hwnd, Win32Constants.WM_GETICON, Win32Constants.ICON_BIG, IntPtr.Zero, Win32Constants.SMTO_ABORTIFHUNG, 100, out var result) != 0 && result != 0)
{ {
icon = System.Drawing.Icon.FromHandle((IntPtr)result); icon = System.Drawing.Icon.FromHandle(result);
NativeMethods.DestroyIcon((IntPtr)result); NativeMethods.DestroyIcon(result);
return true; return true;
} }
if (NativeMethods.SendMessageTimeout(hwnd, Win32Constants.WM_GETICON, (UIntPtr)Win32Constants.ICON_SMALL, IntPtr.Zero, Win32Constants.SMTO_ABORTIFHUNG, 100, out result) != 0 && result != 0) if (NativeMethods.SendMessageTimeout(Hwnd, Win32Constants.WM_GETICON, Win32Constants.ICON_SMALL, IntPtr.Zero, Win32Constants.SMTO_ABORTIFHUNG, 100, out result) != 0 && result != 0)
{ {
icon = System.Drawing.Icon.FromHandle((IntPtr)result); icon = System.Drawing.Icon.FromHandle(result);
NativeMethods.DestroyIcon((IntPtr)result); NativeMethods.DestroyIcon(result);
return true; return true;
} }
if (NativeMethods.SendMessageTimeout(hwnd, Win32Constants.WM_GETICON, (UIntPtr)Win32Constants.ICON_SMALL2, IntPtr.Zero, Win32Constants.SMTO_ABORTIFHUNG, 100, out result) != 0 && result != 0) if (NativeMethods.SendMessageTimeout(Hwnd, Win32Constants.WM_GETICON, Win32Constants.ICON_SMALL2, IntPtr.Zero, Win32Constants.SMTO_ABORTIFHUNG, 100, out result) != 0 && result != 0)
{ {
icon = System.Drawing.Icon.FromHandle((IntPtr)result); icon = System.Drawing.Icon.FromHandle(result);
NativeMethods.DestroyIcon((IntPtr)result); NativeMethods.DestroyIcon(result);
return true; return true;
} }
// Fallback to GetClassLongPtr // Fallback to GetClassLongPtr
var iconHandle = NativeMethods.GetClassLongPtr(hwnd, Win32Constants.GCLP_HICON); var iconHandle = NativeMethods.GetClassLongPtr(Hwnd, Win32Constants.GCLP_HICON);
if (iconHandle != IntPtr.Zero) if (iconHandle != IntPtr.Zero)
{ {
icon = System.Drawing.Icon.FromHandle(iconHandle); icon = System.Drawing.Icon.FromHandle(iconHandle);
NativeMethods.DestroyIcon((IntPtr)iconHandle); NativeMethods.DestroyIcon(iconHandle);
return true; return true;
} }
iconHandle = NativeMethods.GetClassLongPtr(hwnd, Win32Constants.GCLP_HICONSM); iconHandle = NativeMethods.GetClassLongPtr(Hwnd, Win32Constants.GCLP_HICONSM);
if (iconHandle != IntPtr.Zero) if (iconHandle != IntPtr.Zero)
{ {
icon = System.Drawing.Icon.FromHandle(iconHandle); icon = System.Drawing.Icon.FromHandle(iconHandle);
NativeMethods.DestroyIcon((IntPtr)iconHandle); NativeMethods.DestroyIcon(iconHandle);
return true; return true;
} }
@@ -251,16 +231,16 @@ internal sealed class Window
public override string ToString() public override string ToString()
{ {
// Using CurrentCulture since this is user facing // Using CurrentCulture since this is user facing
return Title + " (" + processInfo.Name?.ToUpper(CultureInfo.CurrentCulture) + ")"; return Title + " (" + Process.Name?.ToUpper(CultureInfo.CurrentCulture) + ")";
} }
/// <summary> /// <summary>
/// Returns what the window size is /// Returns what the window size is
/// </summary> /// </summary>
/// <returns>The state (minimized, maximized, etc..) of the window</returns> /// <returns>The state (minimized, maximized, etc...) of the window</returns>
internal WindowSizeState GetWindowSizeState() private WindowSizeState GetWindowSizeState()
{ {
NativeMethods.GetWindowPlacement(Hwnd, out WINDOWPLACEMENT placement); NativeMethods.GetWindowPlacement(Hwnd, out var placement);
switch (placement.ShowCmd) switch (placement.ShowCmd)
{ {
@@ -304,7 +284,7 @@ internal sealed class Window
case (int)DwmWindowCloakStates.CloakedApp: case (int)DwmWindowCloakStates.CloakedApp:
return WindowCloakState.App; return WindowCloakState.App;
case (int)DwmWindowCloakStates.CloakedShell: case (int)DwmWindowCloakStates.CloakedShell:
return WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.IsWindowCloakedByVirtualDesktopManager(hwnd, Desktop.Id) ? WindowCloakState.OtherDesktop : WindowCloakState.Shell; return WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.IsWindowCloakedByVirtualDesktopManager(Hwnd, Desktop.Id) ? WindowCloakState.OtherDesktop : WindowCloakState.Shell;
case (int)DwmWindowCloakStates.CloakedInherited: case (int)DwmWindowCloakStates.CloakedInherited:
return WindowCloakState.Inherited; return WindowCloakState.Inherited;
default: default:
@@ -332,7 +312,7 @@ internal sealed class Window
/// <returns>Class name</returns> /// <returns>Class name</returns>
private static string GetWindowClassName(IntPtr hwnd) private static string GetWindowClassName(IntPtr hwnd)
{ {
StringBuilder windowClassName = new StringBuilder(300); var windowClassName = new StringBuilder(300);
var numCharactersWritten = NativeMethods.GetClassName(hwnd, windowClassName, windowClassName.MaxCapacity); var numCharactersWritten = NativeMethods.GetClassName(hwnd, windowClassName, windowClassName.MaxCapacity);
if (numCharactersWritten == 0) if (numCharactersWritten == 0)
@@ -350,16 +330,16 @@ internal sealed class Window
/// <returns>A new Instance of type <see cref="WindowProcess"/></returns> /// <returns>A new Instance of type <see cref="WindowProcess"/></returns>
private static WindowProcess CreateWindowProcessInstance(IntPtr hWindow) private static WindowProcess CreateWindowProcessInstance(IntPtr hWindow)
{ {
lock (_handlesToProcessCache) lock (HandlesToProcessCache)
{ {
if (_handlesToProcessCache.Count > 7000) if (HandlesToProcessCache.Count > 7000)
{ {
Debug.Print("Clearing Process Cache because it's size is " + _handlesToProcessCache.Count); Debug.Print("Clearing Process Cache because it's size is " + HandlesToProcessCache.Count);
_handlesToProcessCache.Clear(); HandlesToProcessCache.Clear();
} }
// Add window's process to cache if missing // Add window's process to cache if missing
if (!_handlesToProcessCache.ContainsKey(hWindow)) if (!HandlesToProcessCache.ContainsKey(hWindow))
{ {
// Get process ID and name // Get process ID and name
var processId = WindowProcess.GetProcessIDFromWindowHandle(hWindow); var processId = WindowProcess.GetProcessIDFromWindowHandle(hWindow);
@@ -368,23 +348,23 @@ internal sealed class Window
if (processName.Length != 0) if (processName.Length != 0)
{ {
_handlesToProcessCache.Add(hWindow, new WindowProcess(processId, threadId, processName)); HandlesToProcessCache.Add(hWindow, new WindowProcess(processId, threadId, processName));
} }
else else
{ {
// For the dwm process we cannot receive the name. This is no problem because the window isn't part of result list. // For the dwm process we cannot receive the name. This is no problem because the window isn't part of result list.
ExtensionHost.LogMessage(new LogMessage() { Message = $"Invalid process {processId} ({processName}) for window handle {hWindow}." }); ExtensionHost.LogMessage(new LogMessage { Message = $"Invalid process {processId} ({processName}) for window handle {hWindow}." });
_handlesToProcessCache.Add(hWindow, new WindowProcess(0, 0, string.Empty)); HandlesToProcessCache.Add(hWindow, new WindowProcess(0, 0, string.Empty));
} }
} }
// Correct the process data if the window belongs to a uwp app hosted by 'ApplicationFrameHost.exe' // Correct the process data if the window belongs to a uwp app hosted by 'ApplicationFrameHost.exe'
// (This only works if the window isn't minimized. For minimized windows the required child window isn't assigned.) // (This only works if the window isn't minimized. For minimized windows the required child window isn't assigned.)
if (_handlesToProcessCache[hWindow].IsUwpAppFrameHost) if (HandlesToProcessCache[hWindow].IsUwpAppFrameHost)
{ {
new Task(() => new Task(() =>
{ {
EnumWindowsProc callbackptr = new EnumWindowsProc((IntPtr hwnd, IntPtr lParam) => var callbackptr = new EnumWindowsProc((hwnd, _) =>
{ {
// Every uwp app main window has at least three child windows. Only the one we are interested in has a class starting with "Windows.UI.Core." and is assigned to the real app process. // Every uwp app main window has at least three child windows. Only the one we are interested in has a class starting with "Windows.UI.Core." and is assigned to the real app process.
// (The other ones have a class name that begins with the string "ApplicationFrame".) // (The other ones have a class name that begins with the string "ApplicationFrame".)
@@ -395,9 +375,9 @@ internal sealed class Window
var childProcessName = WindowProcess.GetProcessNameFromProcessID(childProcessId); var childProcessName = WindowProcess.GetProcessNameFromProcessID(childProcessId);
// Update process info in cache // Update process info in cache
lock (_handlesToProcessCache) lock (HandlesToProcessCache)
{ {
_handlesToProcessCache[hWindow].UpdateProcessInfo(childProcessId, childThreadId, childProcessName); HandlesToProcessCache[hWindow].UpdateProcessInfo(childProcessId, childThreadId, childProcessName);
} }
return false; return false;
@@ -411,7 +391,7 @@ internal sealed class Window
}).Start(); }).Start();
} }
return _handlesToProcessCache[hWindow]; return HandlesToProcessCache[hWindow];
} }
} }
} }

View File

@@ -1,12 +1,9 @@
// Copyright (c) Microsoft Corporation // Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.CmdPal.Ext.WindowWalker.Commands; using Microsoft.CmdPal.Ext.WindowWalker.Commands;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components; namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
@@ -192,22 +189,27 @@ internal sealed class WindowProcess
/// <summary> /// <summary>
/// Gets the process name for the process ID /// Gets the process name for the process ID
/// </summary> /// </summary>
/// <param name="pid">The id of the process/param> /// <param name="pid">The id of the process</param>
/// <returns>A string representing the process name or an empty string if the function fails</returns> /// <returns>A string representing the process name or an empty string if the function fails</returns>
internal static string GetProcessNameFromProcessID(uint pid) internal static string GetProcessNameFromProcessID(uint pid)
{ {
var processHandle = NativeMethods.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, true, (int)pid); var processHandle = NativeMethods.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, true, (int)pid);
StringBuilder processName = new StringBuilder(MaximumFileNameLength); try
{
var processName = new StringBuilder(MaximumFileNameLength);
var processNameLength = NativeMethods.GetProcessImageFileName(processHandle, processName, MaximumFileNameLength);
if (processNameLength == 0)
{
return string.Empty;
}
if (NativeMethods.GetProcessImageFileName(processHandle, processName, MaximumFileNameLength) != 0) var processNameStr = processName.ToString();
{ var lastSeparatorIndex = processNameStr.LastIndexOf('\\');
_ = Win32Helpers.CloseHandleIfNotNull(processHandle); return lastSeparatorIndex >= 0 ? processNameStr[(lastSeparatorIndex + 1)..] : processNameStr;
return processName.ToString().Split('\\').Reverse().ToArray()[0];
} }
else finally
{ {
_ = Win32Helpers.CloseHandleIfNotNull(processHandle); _ = Win32Helpers.CloseHandleIfNotNull(processHandle);
return string.Empty;
} }
} }

View File

@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
global using System;
global using System.Collections.Generic;
global using System.Text;
global using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
global using Microsoft.CmdPal.Ext.WindowWalker.Properties;
global using Microsoft.CommandPalette.Extensions.Toolkit;

View File

@@ -8,10 +8,8 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
/// <summary> /// <summary>
/// Virtual Desktop Manager class /// Virtual Desktop Manager class
/// Code used from <see href="https://learn.microsoft.com/archive/blogs/winsdk/virtual-desktop-switching-in-windows-10"./> /// Code used from <see href="https://learn.microsoft.com/archive/blogs/winsdk/virtual-desktop-switching-in-windows-10"/>
/// </summary> /// </summary>
[ComImport] [ComImport]
[Guid("aa509086-5ca9-4c25-8f95-589d3c07b48a")] [Guid("aa509086-5ca9-4c25-8f95-589d3c07b48a")]
internal class CVirtualDesktopManager internal class CVirtualDesktopManager;
{
}

View File

@@ -2,7 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling; using System.Runtime.InteropServices.Marshalling;
@@ -10,7 +9,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
/// <summary> /// <summary>
/// Interface for accessing Virtual Desktop Manager. /// Interface for accessing Virtual Desktop Manager.
/// Code used from <see href="https://learn.microsoft.com/archive/blogs/winsdk/virtual-desktop-switching-in-windows-10"./> /// Code used from <see href="https://learn.microsoft.com/archive/blogs/winsdk/virtual-desktop-switching-in-windows-10"/>
/// </summary> /// </summary>
[GeneratedComInterface] [GeneratedComInterface]
[Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")] [Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")]

View File

@@ -2,9 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute; using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
@@ -97,14 +95,6 @@ public static partial class NativeMethods
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern IntPtr GetShellWindow(); public static extern IntPtr GetShellWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumThreadWindows(uint threadId, ShellCommand.EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetFirmwareType(ref FirmwareType FirmwareType);
[DllImport("advapi32.dll", SetLastError = true)] [DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool OpenProcessToken(SafeProcessHandle processHandle, TokenAccess desiredAccess, out SafeAccessTokenHandle tokenHandle); internal static extern bool OpenProcessToken(SafeProcessHandle processHandle, TokenAccess desiredAccess, out SafeAccessTokenHandle tokenHandle);
@@ -265,113 +255,8 @@ public enum HRESULT : uint
E_CANCELLED = 0x800704C7, E_CANCELLED = 0x800704C7,
} }
/// <remarks>
/// <see href="https://learn.microsoft.com/windows/win32/api/winnt/ne-winnt-firmware_type">see learn.microsoft.com</see>
/// </remarks>
public enum FirmwareType
{
Unknown = 0,
Bios = 1,
Uefi = 2,
Max = 3,
}
/// <summary>
/// <see href="https://learn.microsoft.com/windows/win32/stg/stgm-constants">see all STGM values</see>
/// </summary>
[Flags]
public enum STGM : long
{
READ = 0x00000000L,
WRITE = 0x00000001L,
READWRITE = 0x00000002L,
CREATE = 0x00001000L,
}
public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam); public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
/// <summary>
/// Some flags for interop calls to SetWindowPosition
/// </summary>
[Flags]
public enum SetWindowPosFlags : uint
{
/// <summary>
/// If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request.
/// </summary>
SWP_ASYNCWINDOWPOS = 0x4000,
/// <summary>
/// Prevents generation of the WM_SYNCPAINT message.
/// </summary>
SWP_DEFERERASE = 0x2000,
/// <summary>
/// Draws a frame (defined in the window's class description) around the window.
/// </summary>
SWP_DRAWFRAME = 0x0020,
/// <summary>
/// Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed.
/// </summary>
SWP_FRAMECHANGED = 0x0020,
/// <summary>
/// Hides the window.
/// </summary>
SWP_HIDEWINDOW = 0x0080,
/// <summary>
/// Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter).
/// </summary>
SWP_NOACTIVATE = 0x0010,
/// <summary>
/// Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned.
/// </summary>
SWP_NOCOPYBITS = 0x0100,
/// <summary>
/// Retains the current position (ignores X and Y parameters).
/// </summary>
SWP_NOMOVE = 0x0002,
/// <summary>
/// Does not change the owner window's position in the Z order.
/// </summary>
SWP_NOOWNERZORDER = 0x0200,
/// <summary>
/// Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.
/// </summary>
SWP_NOREDRAW = 0x0008,
/// <summary>
/// Same as the SWP_NOOWNERZORDER flag.
/// </summary>
SWP_NOREPOSITION = 0x0200,
/// <summary>
/// Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
/// </summary>
SWP_NOSENDCHANGING = 0x0400,
/// <summary>
/// Retains the current size (ignores the cx and cy parameters).
/// </summary>
SWP_NOSIZE = 0x0001,
/// <summary>
/// Retains the current Z order (ignores the hWndInsertAfter parameter).
/// </summary>
SWP_NOZORDER = 0x0004,
/// <summary>
/// Displays the window.
/// </summary>
SWP_SHOWWINDOW = 0x0040,
}
/// <summary> /// <summary>
/// Options for DwmpActivateLivePreview /// Options for DwmpActivateLivePreview
/// </summary> /// </summary>
@@ -655,16 +540,6 @@ public enum ProcessAccessFlags
AllAccess = StandardRightsRequired | Synchronize | 0xFFFF, AllAccess = StandardRightsRequired | Synchronize | 0xFFFF,
} }
[StructLayout(LayoutKind.Sequential)]
public struct GUIDDATA
{
public int Data1;
public short Data2;
public short Data3;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Data4;
}
/// <summary> /// <summary>
/// Contains information about the placement of a window on the screen. /// Contains information about the placement of a window on the screen.
/// </summary> /// </summary>
@@ -920,7 +795,7 @@ public struct POINT : IEquatable<POINT>
{ {
if (obj is POINT pt) if (obj is POINT pt)
{ {
return this.X == pt.X && this.Y == pt.X; return X == pt.X && Y == pt.X;
} }
return false; return false;
@@ -1145,22 +1020,6 @@ public enum ExtendedWindowStyles : uint
WS_EX_NOACTIVATE = 0x8000000, WS_EX_NOACTIVATE = 0x8000000,
} }
/// <summary>
/// The following are ShellItem DisplayName types.
/// </summary>
[Flags]
public enum SIGDN : uint
{
NORMALDISPLAY = 0,
PARENTRELATIVEPARSING = 0x80018001,
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
DESKTOPABSOLUTEPARSING = 0x80028000,
PARENTRELATIVEEDITING = 0x80031001,
DESKTOPABSOLUTEEDITING = 0x8004c000,
FILESYSPATH = 0x80058000,
URL = 0x80068000,
}
internal enum TOKEN_INFORMATION_CLASS internal enum TOKEN_INFORMATION_CLASS
{ {
TokenIsAppContainer = 29, TokenIsAppContainer = 29,

View File

@@ -2,8 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers; namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
public static class OSVersionHelper public static class OSVersionHelper
@@ -12,9 +10,4 @@ public static class OSVersionHelper
{ {
return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build >= 22000; return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build >= 22000;
} }
public static bool IsGreaterThanWindows11_21H2()
{
return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build > 22000;
}
} }

View File

@@ -2,9 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers; namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;

View File

@@ -3,18 +3,16 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.IO; using System.IO;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers; namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
public class SettingsManager : JsonSettingsManager, ISettingsInterface public class SettingsManager : JsonSettingsManager, ISettingsInterface
{ {
private static readonly string _namespace = "windowWalker"; private const string Namespace = "windowWalker";
private static string Namespaced(string propertyName) => $"{_namespace}.{propertyName}"; private static string Namespaced(string propertyName) => $"{Namespace}.{propertyName}";
private static SettingsManager? instance; private static SettingsManager? _instance;
private readonly ToggleSetting _resultsFromVisibleDesktopOnly = new( private readonly ToggleSetting _resultsFromVisibleDesktopOnly = new(
Namespaced(nameof(ResultsFromVisibleDesktopOnly)), Namespaced(nameof(ResultsFromVisibleDesktopOnly)),
@@ -123,15 +121,15 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
// Load settings from file upon initialization // Load settings from file upon initialization
LoadSettings(); LoadSettings();
Settings.SettingsChanged += (s, a) => this.SaveSettings(); Settings.SettingsChanged += (_, _) => SaveSettings();
} }
internal static SettingsManager Instance internal static SettingsManager Instance
{ {
get get
{ {
instance ??= new SettingsManager(); _instance ??= new SettingsManager();
return instance; return _instance;
} }
} }
} }

View File

@@ -1,83 +0,0 @@
// Copyright (c) Microsoft Corporation
// 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;
using System.Diagnostics;
using System.Text;
using System.Threading;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
public static class ShellCommand
{
public delegate bool EnumThreadDelegate(IntPtr hwnd, IntPtr lParam);
private static bool containsSecurityWindow;
public static Process? RunAsDifferentUser(ProcessStartInfo processStartInfo)
{
ArgumentNullException.ThrowIfNull(processStartInfo);
processStartInfo.Verb = "RunAsUser";
var process = Process.Start(processStartInfo);
containsSecurityWindow = false;
// wait for windows to bring up the "Windows Security" dialog
while (!containsSecurityWindow)
{
CheckSecurityWindow();
Thread.Sleep(25);
}
// while this process contains a "Windows Security" dialog, stay open
while (containsSecurityWindow)
{
containsSecurityWindow = false;
CheckSecurityWindow();
Thread.Sleep(50);
}
return process;
}
private static void CheckSecurityWindow()
{
ProcessThreadCollection ptc = Process.GetCurrentProcess().Threads;
for (var i = 0; i < ptc.Count; i++)
{
NativeMethods.EnumThreadWindows((uint)ptc[i].Id, CheckSecurityThread, IntPtr.Zero);
}
}
private static bool CheckSecurityThread(IntPtr hwnd, IntPtr lParam)
{
if (GetWindowTitle(hwnd) == "Windows Security")
{
containsSecurityWindow = true;
}
return true;
}
private static string GetWindowTitle(IntPtr hwnd)
{
StringBuilder sb = new StringBuilder(NativeMethods.GetWindowTextLength(hwnd) + 1);
_ = NativeMethods.GetWindowText(hwnd, sb, sb.Capacity);
return sb.ToString();
}
public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", string arguments = "", string verb = "")
{
var info = new ProcessStartInfo
{
FileName = fileName,
WorkingDirectory = workingDirectory,
Arguments = arguments,
Verb = verb,
};
return info;
}
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation // Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers; namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;

View File

@@ -2,16 +2,11 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling; using System.Runtime.InteropServices.Marshalling;
using System.Text;
using ManagedCsWin32; using ManagedCsWin32;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Win32; using Microsoft.Win32;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers; namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
@@ -55,7 +50,7 @@ public class VirtualDesktopHelper
/// </summary> /// </summary>
private Guid _currentDesktop; private Guid _currentDesktop;
private static readonly CompositeFormat VirtualDesktopHelperDesktop = System.Text.CompositeFormat.Parse(Properties.Resources.VirtualDesktopHelper_Desktop); private static readonly CompositeFormat VirtualDesktopHelperDesktop = CompositeFormat.Parse(Resources.VirtualDesktopHelper_Desktop);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="VirtualDesktopHelper"/> class. /// Initializes a new instance of the <see cref="VirtualDesktopHelper"/> class.
@@ -71,7 +66,7 @@ public class VirtualDesktopHelper
} }
catch (COMException ex) catch (COMException ex)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"Initialization of <VirtualDesktopHelper> failed: An exception was thrown when creating the instance of COM interface <IVirtualDesktopManager>. {ex} " }); ExtensionHost.LogMessage(new LogMessage { Message = $"Initialization of <VirtualDesktopHelper> failed: An exception was thrown when creating the instance of COM interface <IVirtualDesktopManager>. {ex} " });
return; return;
} }
@@ -97,33 +92,27 @@ public class VirtualDesktopHelper
var registryExplorerVirtualDesktops = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops"; // Windows 11 var registryExplorerVirtualDesktops = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops"; // Windows 11
// List of all desktops // List of all desktops
using RegistryKey? virtualDesktopKey = Registry.CurrentUser.OpenSubKey(registryExplorerVirtualDesktops, false); using var virtualDesktopKey = Registry.CurrentUser.OpenSubKey(registryExplorerVirtualDesktops, false);
if (virtualDesktopKey is not null) if (virtualDesktopKey is not null)
{ {
var allDeskValue = (byte[]?)virtualDesktopKey.GetValue("VirtualDesktopIDs", null) ?? Array.Empty<byte>(); var allDeskValue = (byte[]?)virtualDesktopKey.GetValue("VirtualDesktopIDs", null) ?? [];
if (allDeskValue is not null)
{
// We clear only, if we can read from registry. Otherwise, we keep the existing values.
_availableDesktops.Clear();
// Each guid has a length of 16 elements // We clear only, if we can read from registry. Otherwise, we keep the existing values.
var numberOfDesktops = allDeskValue.Length / 16; _availableDesktops.Clear();
for (var i = 0; i < numberOfDesktops; i++)
{ // Each guid has a length of 16 elements
var guidArray = new byte[16]; var numberOfDesktops = allDeskValue.Length / 16;
Array.ConstrainedCopy(allDeskValue, i * 16, guidArray, 0, 16); for (var i = 0; i < numberOfDesktops; i++)
_availableDesktops.Add(new Guid(guidArray));
}
}
else
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"VirtualDesktopHelper.UpdateDesktopList() failed to read the list of existing desktops form registry." }); var guidArray = new byte[16];
Array.ConstrainedCopy(allDeskValue, i * 16, guidArray, 0, 16);
_availableDesktops.Add(new Guid(guidArray));
} }
} }
// Guid for current desktop // Guid for current desktop
var virtualDesktopsKeyName = _isWindowsEleven ? registryExplorerVirtualDesktops : registrySessionVirtualDesktops; var virtualDesktopsKeyName = _isWindowsEleven ? registryExplorerVirtualDesktops : registrySessionVirtualDesktops;
using RegistryKey? virtualDesktopsKey = Registry.CurrentUser.OpenSubKey(virtualDesktopsKeyName, false); using var virtualDesktopsKey = Registry.CurrentUser.OpenSubKey(virtualDesktopsKeyName, false);
if (virtualDesktopsKey is not null) if (virtualDesktopsKey is not null)
{ {
var currentVirtualDesktopValue = virtualDesktopsKey.GetValue("CurrentVirtualDesktop", null); var currentVirtualDesktopValue = virtualDesktopsKey.GetValue("CurrentVirtualDesktop", null);
@@ -135,7 +124,7 @@ public class VirtualDesktopHelper
{ {
// The registry value is missing when the user hasn't switched the desktop at least one time before reading the registry. In this case we can set it to desktop one. // The registry value is missing when the user hasn't switched the desktop at least one time before reading the registry. In this case we can set it to desktop one.
// We can only set it to desktop one, if we have at least one desktop in the desktops list. Otherwise, we keep the existing value. // We can only set it to desktop one, if we have at least one desktop in the desktops list. Otherwise, we keep the existing value.
ExtensionHost.LogMessage(new LogMessage() { Message = "VirtualDesktopHelper.UpdateDesktopList() failed to read the id for the current desktop form registry." }); ExtensionHost.LogMessage(new LogMessage { Message = "VirtualDesktopHelper.UpdateDesktopList() failed to read the id for the current desktop form registry." });
_currentDesktop = _availableDesktops.Count >= 1 ? _availableDesktops[0] : _currentDesktop; _currentDesktop = _availableDesktops.Count >= 1 ? _availableDesktops[0] : _currentDesktop;
} }
} }
@@ -166,8 +155,8 @@ public class VirtualDesktopHelper
UpdateDesktopList(); UpdateDesktopList();
} }
List<VDesktop> list = new List<VDesktop>(); var list = new List<VDesktop>();
foreach (Guid d in _availableDesktops) foreach (var d in _availableDesktops)
{ {
list.Add(CreateVDesktopInstance(d)); list.Add(CreateVDesktopInstance(d));
} }
@@ -257,7 +246,7 @@ public class VirtualDesktopHelper
{ {
if (desktop == Guid.Empty || !GetDesktopIdList().Contains(desktop)) if (desktop == Guid.Empty || !GetDesktopIdList().Contains(desktop))
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"VirtualDesktopHelper.GetDesktopName() failed. Parameter contains an invalid desktop guid ({desktop}) that doesn't belongs to an available desktop. Maybe the guid belongs to the generic 'AllDesktops' view." }); ExtensionHost.LogMessage(new LogMessage { Message = $"VirtualDesktopHelper.GetDesktopName() failed. Parameter contains an invalid desktop guid ({desktop}) that doesn't belongs to an available desktop. Maybe the guid belongs to the generic 'AllDesktops' view." });
return string.Empty; return string.Empty;
} }
@@ -265,7 +254,7 @@ public class VirtualDesktopHelper
var defaultName = string.Format(System.Globalization.CultureInfo.InvariantCulture, VirtualDesktopHelperDesktop, GetDesktopNumber(desktop)); var defaultName = string.Format(System.Globalization.CultureInfo.InvariantCulture, VirtualDesktopHelperDesktop, GetDesktopNumber(desktop));
var registryPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops\\Desktops\\{" + desktop.ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture) + "}"; var registryPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops\\Desktops\\{" + desktop.ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture) + "}";
using RegistryKey? deskSubKey = Registry.CurrentUser.OpenSubKey(registryPath, false); using var deskSubKey = Registry.CurrentUser.OpenSubKey(registryPath, false);
var desktopName = deskSubKey?.GetValue("Name"); var desktopName = deskSubKey?.GetValue("Name");
return (desktopName is not null) ? (string)desktopName : defaultName; return (desktopName is not null) ? (string)desktopName : defaultName;
@@ -275,7 +264,7 @@ public class VirtualDesktopHelper
/// Returns the position type for a desktop. /// Returns the position type for a desktop.
/// </summary> /// </summary>
/// <param name="desktop">Guid of the desktop.</param> /// <param name="desktop">Guid of the desktop.</param>
/// <returns>Type of <see cref="VirtualDesktopPosition"/>. On failure we return <see cref="VirtualDesktopPosition.Unknown"/>.</returns> /// <returns>Type of <see cref="VirtualDesktopPosition"/> or <see cref="VirtualDesktopPosition.NotApplicable"/>.</returns>
public VirtualDesktopPosition GetDesktopPositionType(Guid desktop) public VirtualDesktopPosition GetDesktopPositionType(Guid desktop)
{ {
var desktopNumber = GetDesktopNumber(desktop); var desktopNumber = GetDesktopNumber(desktop);
@@ -315,7 +304,7 @@ public class VirtualDesktopHelper
{ {
if (_virtualDesktopManager is null) if (_virtualDesktopManager is null)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = "VirtualDesktopHelper.GetWindowDesktopId() failed: The instance of <IVirtualDesktopHelper> isn't available." }); ExtensionHost.LogMessage(new LogMessage { Message = "VirtualDesktopHelper.GetWindowDesktopId() failed: The instance of <IVirtualDesktopHelper> isn't available." });
desktopId = Guid.Empty; desktopId = Guid.Empty;
return unchecked((int)HRESULT.E_UNEXPECTED); return unchecked((int)HRESULT.E_UNEXPECTED);
} }
@@ -332,11 +321,11 @@ public class VirtualDesktopHelper
{ {
if (_virtualDesktopManager is null) if (_virtualDesktopManager is null)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = "VirtualDesktopHelper.GetWindowDesktop() failed: The instance of <IVirtualDesktopHelper> isn't available." }); ExtensionHost.LogMessage(new LogMessage { Message = "VirtualDesktopHelper.GetWindowDesktop() failed: The instance of <IVirtualDesktopHelper> isn't available." });
return CreateVDesktopInstance(Guid.Empty); return CreateVDesktopInstance(Guid.Empty);
} }
var hr = _virtualDesktopManager.GetWindowDesktopId(hWindow, out Guid desktopId); var hr = _virtualDesktopManager.GetWindowDesktopId(hWindow, out var desktopId);
return (hr != (int)HRESULT.S_OK || desktopId == Guid.Empty) ? VDesktop.Empty : CreateVDesktopInstance(desktopId, hWindow); return (hr != (int)HRESULT.S_OK || desktopId == Guid.Empty) ? VDesktop.Empty : CreateVDesktopInstance(desktopId, hWindow);
} }
@@ -350,12 +339,12 @@ public class VirtualDesktopHelper
{ {
if (_virtualDesktopManager is null) if (_virtualDesktopManager is null)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = "VirtualDesktopHelper.GetWindowDesktopAssignmentType() failed: The instance of <IVirtualDesktopHelper> isn't available." }); ExtensionHost.LogMessage(new LogMessage { Message = "VirtualDesktopHelper.GetWindowDesktopAssignmentType() failed: The instance of <IVirtualDesktopHelper> isn't available." });
return VirtualDesktopAssignmentType.Unknown; return VirtualDesktopAssignmentType.Unknown;
} }
_ = _virtualDesktopManager.IsWindowOnCurrentVirtualDesktop(hWindow, out var isOnCurrentDesktop); _ = _virtualDesktopManager.IsWindowOnCurrentVirtualDesktop(hWindow, out var isOnCurrentDesktop);
Guid windowDesktopId = desktop ?? Guid.Empty; // Prepare variable in case we have no input parameter for desktop var windowDesktopId = desktop ?? Guid.Empty; // Prepare variable in case we have no input parameter for desktop
var hResult = desktop is null ? GetWindowDesktopId(hWindow, out windowDesktopId) : 0; var hResult = desktop is null ? GetWindowDesktopId(hWindow, out windowDesktopId) : 0;
if (hResult != (int)HRESULT.S_OK) if (hResult != (int)HRESULT.S_OK)
@@ -417,14 +406,14 @@ public class VirtualDesktopHelper
{ {
if (_virtualDesktopManager is null) if (_virtualDesktopManager is null)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = "VirtualDesktopHelper.MoveWindowToDesktop() failed: The instance of <IVirtualDesktopHelper> isn't available." }); ExtensionHost.LogMessage(new LogMessage { Message = "VirtualDesktopHelper.MoveWindowToDesktop() failed: The instance of <IVirtualDesktopHelper> isn't available." });
return false; return false;
} }
var hr = _virtualDesktopManager.MoveWindowToDesktop(hWindow, ref desktopId); var hr = _virtualDesktopManager.MoveWindowToDesktop(hWindow, ref desktopId);
if (hr != (int)HRESULT.S_OK) if (hr != (int)HRESULT.S_OK)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = "VirtualDesktopHelper.MoveWindowToDesktop() failed: An exception was thrown when moving the window ({hWindow}) to another desktop ({desktopId})." }); ExtensionHost.LogMessage(new LogMessage { Message = "VirtualDesktopHelper.MoveWindowToDesktop() failed: An exception was thrown when moving the window ({hWindow}) to another desktop ({desktopId})." });
return false; return false;
} }
@@ -438,27 +427,27 @@ public class VirtualDesktopHelper
/// <returns><see langword="True"/> on success and <see langword="false"/> on failure.</returns> /// <returns><see langword="True"/> on success and <see langword="false"/> on failure.</returns>
public bool MoveWindowOneDesktopLeft(IntPtr hWindow) public bool MoveWindowOneDesktopLeft(IntPtr hWindow)
{ {
var hr = GetWindowDesktopId(hWindow, out Guid windowDesktop); var hr = GetWindowDesktopId(hWindow, out var windowDesktop);
if (hr != (int)HRESULT.S_OK) if (hr != (int)HRESULT.S_OK)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: Can't get current desktop of the window." }); ExtensionHost.LogMessage(new LogMessage { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: Can't get current desktop of the window." });
return false; return false;
} }
if (GetDesktopIdList().Count == 0 || GetWindowDesktopAssignmentType(hWindow, windowDesktop) == VirtualDesktopAssignmentType.Unknown || GetWindowDesktopAssignmentType(hWindow, windowDesktop) == VirtualDesktopAssignmentType.NotAssigned) if (GetDesktopIdList().Count == 0 || GetWindowDesktopAssignmentType(hWindow, windowDesktop) == VirtualDesktopAssignmentType.Unknown || GetWindowDesktopAssignmentType(hWindow, windowDesktop) == VirtualDesktopAssignmentType.NotAssigned)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: We can't find the target desktop. This can happen if the desktop list is empty or if the window isn't assigned to a specific desktop." }); ExtensionHost.LogMessage(new LogMessage { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: We can't find the target desktop. This can happen if the desktop list is empty or if the window isn't assigned to a specific desktop." });
return false; return false;
} }
var windowDesktopNumber = GetDesktopIdList().IndexOf(windowDesktop); var windowDesktopNumber = GetDesktopIdList().IndexOf(windowDesktop);
if (windowDesktopNumber == 1) if (windowDesktopNumber == 1)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: The window is on the first desktop." }); ExtensionHost.LogMessage(new LogMessage { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: The window is on the first desktop." });
return false; return false;
} }
Guid newDesktop = _availableDesktops[windowDesktopNumber - 1]; var newDesktop = _availableDesktops[windowDesktopNumber - 1];
return MoveWindowToDesktop(hWindow, ref newDesktop); return MoveWindowToDesktop(hWindow, ref newDesktop);
} }
@@ -469,27 +458,27 @@ public class VirtualDesktopHelper
/// <returns><see langword="True"/> on success and <see langword="false"/> on failure.</returns> /// <returns><see langword="True"/> on success and <see langword="false"/> on failure.</returns>
public bool MoveWindowOneDesktopRight(IntPtr hWindow) public bool MoveWindowOneDesktopRight(IntPtr hWindow)
{ {
var hr = GetWindowDesktopId(hWindow, out Guid windowDesktop); var hr = GetWindowDesktopId(hWindow, out var windowDesktop);
if (hr != (int)HRESULT.S_OK) if (hr != (int)HRESULT.S_OK)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: Can't get current desktop of the window." }); ExtensionHost.LogMessage(new LogMessage { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: Can't get current desktop of the window." });
return false; return false;
} }
if (GetDesktopIdList().Count == 0 || GetWindowDesktopAssignmentType(hWindow, windowDesktop) == VirtualDesktopAssignmentType.Unknown || GetWindowDesktopAssignmentType(hWindow, windowDesktop) == VirtualDesktopAssignmentType.NotAssigned) if (GetDesktopIdList().Count == 0 || GetWindowDesktopAssignmentType(hWindow, windowDesktop) == VirtualDesktopAssignmentType.Unknown || GetWindowDesktopAssignmentType(hWindow, windowDesktop) == VirtualDesktopAssignmentType.NotAssigned)
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: We can't find the target desktop. This can happen if the desktop list is empty or if the window isn't assigned to a specific desktop." }); ExtensionHost.LogMessage(new LogMessage { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: We can't find the target desktop. This can happen if the desktop list is empty or if the window isn't assigned to a specific desktop." });
return false; return false;
} }
var windowDesktopNumber = GetDesktopIdList().IndexOf(windowDesktop); var windowDesktopNumber = GetDesktopIdList().IndexOf(windowDesktop);
if (windowDesktopNumber == GetDesktopCount()) if (windowDesktopNumber == GetDesktopCount())
{ {
ExtensionHost.LogMessage(new LogMessage() { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: The window is on the last desktop." }); ExtensionHost.LogMessage(new LogMessage { Message = $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: The window is on the last desktop." });
return false; return false;
} }
Guid newDesktop = _availableDesktops[windowDesktopNumber + 1]; var newDesktop = _availableDesktops[windowDesktopNumber + 1];
return MoveWindowToDesktop(hWindow, ref newDesktop); return MoveWindowToDesktop(hWindow, ref newDesktop);
} }
@@ -507,11 +496,11 @@ public class VirtualDesktopHelper
} }
// Can be only detected if method is invoked with window handle parameter. // Can be only detected if method is invoked with window handle parameter.
VirtualDesktopAssignmentType desktopType = (hWindow != default) ? GetWindowDesktopAssignmentType(hWindow, desktop) : VirtualDesktopAssignmentType.Unknown; var desktopType = (hWindow != default) ? GetWindowDesktopAssignmentType(hWindow, desktop) : VirtualDesktopAssignmentType.Unknown;
var isAllDesktops = (hWindow != default) && desktopType == VirtualDesktopAssignmentType.AllDesktops; var isAllDesktops = (hWindow != default) && desktopType == VirtualDesktopAssignmentType.AllDesktops;
var isDesktopVisible = (hWindow != default) ? (isAllDesktops || desktopType == VirtualDesktopAssignmentType.CurrentDesktop) : IsDesktopVisible(desktop); var isDesktopVisible = (hWindow != default) ? (isAllDesktops || desktopType == VirtualDesktopAssignmentType.CurrentDesktop) : IsDesktopVisible(desktop);
return new VDesktop() return new VDesktop
{ {
Id = desktop, Id = desktop,
Name = isAllDesktops ? Resources.VirtualDesktopHelper_AllDesktops : GetDesktopName(desktop), Name = isAllDesktops ? Resources.VirtualDesktopHelper_AllDesktops : GetDesktopName(desktop),

View File

@@ -2,24 +2,12 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers; namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
public static class Win32Helpers public static class Win32Helpers
{ {
/// <summary>
/// Detects the type of system firmware which is equal to the boot type by calling the method <see cref="NativeMethods.GetFirmwareType"/>.
/// </summary>
/// <returns>Firmware type like Uefi or Bios.</returns>
public static FirmwareType GetSystemFirmwareType()
{
FirmwareType firmwareType = default;
_ = NativeMethods.GetFirmwareType(ref firmwareType);
return firmwareType;
}
/// <summary> /// <summary>
/// Returns the last Win32 Error code thrown by a native method if enabled for this method. /// Returns the last Win32 Error code thrown by a native method if enabled for this method.
/// </summary> /// </summary>
@@ -44,14 +32,4 @@ public static class Win32Helpers
return NativeMethods.CloseHandle(handle); return NativeMethods.CloseHandle(handle);
} }
/// <summary>
/// Gets the description for an HRESULT error code.
/// </summary>
/// <param name="hr">The HRESULT number</param>
/// <returns>A string containing the description.</returns>
public static string MessageFromHResult(int hr)
{
return Marshal.GetExceptionForHR(hr)?.Message ?? string.Empty;
}
} }

View File

@@ -2,19 +2,17 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker; namespace Microsoft.CmdPal.Ext.WindowWalker;
internal sealed class Icons internal static class Icons
{ {
internal static IconInfo WindowWalkerIcon { get; } = IconHelpers.FromRelativePath("Assets\\WindowWalker.svg"); internal static IconInfo WindowWalkerIcon { get; } = IconHelpers.FromRelativePath("Assets\\WindowWalker.svg");
internal static IconInfo EndTask { get; } = new IconInfo("\uF140"); // StatusCircleBlock internal static IconInfo EndTask { get; } = new("\uF140"); // StatusCircleBlock
internal static IconInfo CloseWindow { get; } = new IconInfo("\uE894"); // Clear internal static IconInfo CloseWindow { get; } = new("\uE894"); // Clear
internal static IconInfo Info { get; } = new IconInfo("\uE946"); // Info internal static IconInfo Info { get; } = new("\uE946"); // Info
internal static IconInfo GenericAppIcon { get; } = new("\uE737"); // Favicon internal static IconInfo GenericAppIcon { get; } = new("\uE737"); // Favicon
} }

View File

@@ -2,26 +2,18 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Commands; using Microsoft.CmdPal.Ext.WindowWalker.Commands;
using Microsoft.CmdPal.Ext.WindowWalker.Components; using Microsoft.CmdPal.Ext.WindowWalker.Components;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker; namespace Microsoft.CmdPal.Ext.WindowWalker.Pages;
internal sealed partial class WindowWalkerListItem : ListItem internal sealed partial class WindowWalkerListItem : ListItem
{ {
private readonly Window? _window; public Window? Window { get; }
public Window? Window => _window;
public WindowWalkerListItem(Window? window) public WindowWalkerListItem(Window? window)
: base(new SwitchToWindowCommand(window)) : base(new SwitchToWindowCommand(window))
{ {
_window = window; Window = window;
} }
} }

View File

@@ -2,12 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using Microsoft.CmdPal.Ext.WindowWalker.Components; using Microsoft.CmdPal.Ext.WindowWalker.Components;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Pages; namespace Microsoft.CmdPal.Ext.WindowWalker.Pages;
@@ -41,8 +37,8 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
{ {
ArgumentNullException.ThrowIfNull(query); ArgumentNullException.ThrowIfNull(query);
_cancellationTokenSource?.Cancel(); _cancellationTokenSource.Cancel();
_cancellationTokenSource?.Dispose(); _cancellationTokenSource.Dispose();
_cancellationTokenSource = new System.Threading.CancellationTokenSource(); _cancellationTokenSource = new System.Threading.CancellationTokenSource();
WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.UpdateDesktopList(); WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.UpdateDesktopList();
@@ -54,7 +50,7 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
{ {
if (!SettingsManager.Instance.InMruOrder) if (!SettingsManager.Instance.InMruOrder)
{ {
windows.Sort(static (a, b) => string.Compare(a?.Title, b?.Title, StringComparison.OrdinalIgnoreCase)); windows.Sort(static (a, b) => string.Compare(a.Title, b.Title, StringComparison.OrdinalIgnoreCase));
} }
var results = new Scored<Window>[windows.Count]; var results = new Scored<Window>[windows.Count];
@@ -73,7 +69,7 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
private static int ScoreFunction(string q, Window window) private static int ScoreFunction(string q, Window window)
{ {
var titleScore = FuzzyStringMatcher.ScoreFuzzy(q, window.Title); var titleScore = FuzzyStringMatcher.ScoreFuzzy(q, window.Title);
var processNameScore = FuzzyStringMatcher.ScoreFuzzy(q, window.Process?.Name ?? string.Empty); var processNameScore = FuzzyStringMatcher.ScoreFuzzy(q, window.Process.Name ?? string.Empty);
return Math.Max(titleScore, processNameScore); return Math.Max(titleScore, processNameScore);
} }
@@ -91,7 +87,7 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
{ {
if (disposing) if (disposing)
{ {
_cancellationTokenSource?.Dispose(); _cancellationTokenSource.Dispose();
_disposed = true; _disposed = true;
} }
} }

View File

@@ -2,11 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
using Microsoft.CmdPal.Ext.WindowWalker.Pages; using Microsoft.CmdPal.Ext.WindowWalker.Pages;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker; namespace Microsoft.CmdPal.Ext.WindowWalker;