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.
// 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.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
@@ -29,7 +22,7 @@ internal sealed partial class CloseWindowCommand : InvokableCommand
{
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();

View File

@@ -2,16 +2,8 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
@@ -36,7 +28,7 @@ internal sealed partial class EndTaskCommand : InvokableCommand
// Validate process
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
return false;

View File

@@ -2,26 +2,14 @@
// 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.Collections.Generic;
using System.ComponentModel;
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.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
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)
{
using var process = new Process();
@@ -47,7 +35,7 @@ internal sealed partial class ExplorerInfoResultCommand : InvokableCommand
}
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;
}
}

View File

@@ -2,15 +2,10 @@
// 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.Drawing;
using System.IO;
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.Toolkit;
using Windows.Storage.Streams;
namespace Microsoft.CmdPal.Ext.WindowWalker.Commands;
@@ -58,16 +53,13 @@ internal sealed partial class SwitchToWindowCommand : InvokableCommand
else
{
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)
{
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();
}

View File

@@ -2,29 +2,29 @@
// 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.Collections.Generic;
using Microsoft.CmdPal.Ext.WindowWalker.Commands;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.CmdPal.Ext.WindowWalker.Pages;
using Windows.System;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
internal sealed class ContextMenuHelper
internal static class ContextMenuHelper
{
internal static List<CommandContextItem> GetContextMenuResults(in WindowWalkerListItem listItem)
{
if (listItem?.Window is not Window windowData)
ArgumentNullException.ThrowIfNull(listItem);
if (listItem.Window is null)
{
return [];
}
var contextMenu = new List<CommandContextItem>()
var windowData = listItem.Window;
var contextMenu = new List<CommandContextItem>
{
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))
{
RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.Delete, 0),
RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.Delete),
IsCritical = true,
});
}

View File

@@ -3,15 +3,12 @@
// See the LICENSE file in the project root for more information.
// 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;
/// <summary>
/// Class containing methods to control the live preview
/// </summary>
internal sealed class LivePreview
internal static class LivePreview
{
/// <summary>
/// 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.
// Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
@@ -20,27 +17,27 @@ internal sealed class OpenWindows
/// <summary>
/// Used to enforce single execution of EnumWindows
/// </summary>
private static readonly object _enumWindowsLock = new();
private static readonly Lock EnumWindowsLock = new();
/// <summary>
/// PowerLauncher main executable
/// </summary>
private static readonly string? _powerLauncherExe = Path.GetFileName(Environment.ProcessPath);
private static readonly string? PowerLauncherExe = Path.GetFileName(Environment.ProcessPath);
/// <summary>
/// List of all the open windows
/// </summary>
private readonly List<Window> windows = new();
private readonly List<Window> _windows = [];
/// <summary>
/// An instance of the class OpenWindows
/// </summary>
private static OpenWindows? instance;
private static OpenWindows? _instance;
/// <summary>
/// Gets the list of all open windows
/// </summary>
internal List<Window> Windows => new(windows);
internal List<Window> Windows => [.._windows];
/// <summary>
/// Gets an instance property of this class that makes sure that
@@ -51,9 +48,9 @@ internal sealed class OpenWindows
{
get
{
instance ??= new OpenWindows();
_instance ??= new OpenWindows();
return instance;
return _instance;
}
}
@@ -75,10 +72,10 @@ internal sealed class OpenWindows
try
{
var tokenHandleParam = GCHandle.ToIntPtr(tokenHandle);
lock (_enumWindowsLock)
lock (EnumWindowsLock)
{
windows.Clear();
EnumWindowsProc callbackptr = new EnumWindowsProc(WindowEnumerationCallBack);
_windows.Clear();
var callbackptr = new EnumWindowsProc(WindowEnumerationCallBack);
_ = 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
/// in the future</param>
/// <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 target = (CancellationToken?)tokenHandle.Target ?? CancellationToken.None;
@@ -109,18 +106,18 @@ internal sealed class OpenWindows
return false;
}
Window newWindow = new Window(hwnd);
var newWindow = new Window(hwnd);
if (newWindow.IsWindow && newWindow.Visible && newWindow.IsOwner &&
(!newWindow.IsToolWindow || newWindow.IsAppWindow) && !newWindow.TaskListDeleted &&
(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.)
// (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)
{
windows.Add(newWindow);
_windows.Add(newWindow);
}
}

View File

@@ -1,13 +1,10 @@
// 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.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Commands;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.CmdPal.Ext.WindowWalker.Pages;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
@@ -34,10 +31,6 @@ internal static class ResultHelper
for (var i = 0; i < list.Count; i++)
{
var window = list[i].Item;
if (window?.Process is null)
{
continue;
}
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.
// Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
@@ -20,26 +15,11 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
/// </summary>
internal sealed class Window
{
/// <summary>
/// The handle to the window
/// </summary>
private readonly IntPtr hwnd;
/// <summary>
/// A static cache for the process data of all known windows
/// that we don't have to query the data every time
/// </summary>
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;
private static readonly Dictionary<IntPtr, WindowProcess> HandlesToProcessCache = new();
/// <summary>
/// Gets the title of the window (the string displayed at the top of the window)
@@ -48,11 +28,11 @@ internal sealed class Window
{
get
{
var sizeOfTitle = NativeMethods.GetWindowTextLength(hwnd);
var sizeOfTitle = NativeMethods.GetWindowTextLength(Hwnd);
if (sizeOfTitle++ > 0)
{
StringBuilder titleBuffer = new StringBuilder(sizeOfTitle);
var numCharactersWritten = NativeMethods.GetWindowText(hwnd, titleBuffer, sizeOfTitle);
var titleBuffer = new StringBuilder(sizeOfTitle);
var numCharactersWritten = NativeMethods.GetWindowText(Hwnd, titleBuffer, sizeOfTitle);
if (numCharactersWritten == 0)
{
return string.Empty;
@@ -70,17 +50,17 @@ internal sealed class Window
/// <summary>
/// Gets the handle to the window
/// </summary>
internal IntPtr Hwnd => hwnd;
internal IntPtr Hwnd { get; }
/// <summary>
/// Gets the object of with the process information of the window
/// </summary>
internal WindowProcess Process => processInfo;
internal WindowProcess Process { get; }
/// <summary>
/// Gets the object of with the desktop information of the window
/// </summary>
internal VDesktop Desktop => desktopInfo;
internal VDesktop Desktop { get; }
/// <summary>
/// Gets the name of the class for the window represented
@@ -130,7 +110,7 @@ internal sealed class Window
/// <summary>
/// Gets a value indicating whether the window is minimized
/// </summary>
internal bool Minimized => GetWindowSizeState() == WindowSizeState.Minimized;
private bool Minimized => GetWindowSizeState() == WindowSizeState.Minimized;
/// <summary>
/// Initializes a new instance of the <see cref="Window"/> class.
@@ -140,9 +120,9 @@ internal sealed class Window
internal Window(IntPtr hwnd)
{
// TODO: Add verification as to whether the window handle is valid
this.hwnd = hwnd;
processInfo = CreateWindowProcessInstance(hwnd);
desktopInfo = WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.GetWindowDesktop(hwnd);
Hwnd = hwnd;
Process = CreateWindowProcessInstance(hwnd);
Desktop = WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.GetWindowDesktop(hwnd);
}
/// <summary>
@@ -155,7 +135,7 @@ internal sealed class Window
// to use ShowWindow for switching tabs in IE
// 2) SetForegroundWindow fails on minimized windows
// 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);
}
@@ -174,7 +154,7 @@ internal sealed class Window
/// <summary>
/// Helper function to close the window
/// </summary>
internal void CloseThisWindowHelper()
private void CloseThisWindowHelper()
{
_ = NativeMethods.SendMessageTimeout(Hwnd, Win32Constants.WM_SYSCOMMAND, Win32Constants.SC_CLOSE, 0, 0x0000, 5000, out _);
}
@@ -184,7 +164,7 @@ internal sealed class Window
/// </summary>
internal void CloseThisWindow()
{
Thread thread = new(new ThreadStart(CloseThisWindowHelper));
Thread thread = new(CloseThisWindowHelper);
thread.Start();
}
@@ -197,47 +177,47 @@ internal sealed class Window
{
icon = null;
if (hwnd == IntPtr.Zero)
if (Hwnd == IntPtr.Zero)
{
return false;
}
// 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);
NativeMethods.DestroyIcon((IntPtr)result);
icon = System.Drawing.Icon.FromHandle(result);
NativeMethods.DestroyIcon(result);
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);
NativeMethods.DestroyIcon((IntPtr)result);
icon = System.Drawing.Icon.FromHandle(result);
NativeMethods.DestroyIcon(result);
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);
NativeMethods.DestroyIcon((IntPtr)result);
icon = System.Drawing.Icon.FromHandle(result);
NativeMethods.DestroyIcon(result);
return true;
}
// Fallback to GetClassLongPtr
var iconHandle = NativeMethods.GetClassLongPtr(hwnd, Win32Constants.GCLP_HICON);
var iconHandle = NativeMethods.GetClassLongPtr(Hwnd, Win32Constants.GCLP_HICON);
if (iconHandle != IntPtr.Zero)
{
icon = System.Drawing.Icon.FromHandle(iconHandle);
NativeMethods.DestroyIcon((IntPtr)iconHandle);
NativeMethods.DestroyIcon(iconHandle);
return true;
}
iconHandle = NativeMethods.GetClassLongPtr(hwnd, Win32Constants.GCLP_HICONSM);
iconHandle = NativeMethods.GetClassLongPtr(Hwnd, Win32Constants.GCLP_HICONSM);
if (iconHandle != IntPtr.Zero)
{
icon = System.Drawing.Icon.FromHandle(iconHandle);
NativeMethods.DestroyIcon((IntPtr)iconHandle);
NativeMethods.DestroyIcon(iconHandle);
return true;
}
@@ -251,16 +231,16 @@ internal sealed class Window
public override string ToString()
{
// Using CurrentCulture since this is user facing
return Title + " (" + processInfo.Name?.ToUpper(CultureInfo.CurrentCulture) + ")";
return Title + " (" + Process.Name?.ToUpper(CultureInfo.CurrentCulture) + ")";
}
/// <summary>
/// Returns what the window size is
/// </summary>
/// <returns>The state (minimized, maximized, etc..) of the window</returns>
internal WindowSizeState GetWindowSizeState()
/// <returns>The state (minimized, maximized, etc...) of the window</returns>
private WindowSizeState GetWindowSizeState()
{
NativeMethods.GetWindowPlacement(Hwnd, out WINDOWPLACEMENT placement);
NativeMethods.GetWindowPlacement(Hwnd, out var placement);
switch (placement.ShowCmd)
{
@@ -304,7 +284,7 @@ internal sealed class Window
case (int)DwmWindowCloakStates.CloakedApp:
return WindowCloakState.App;
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:
return WindowCloakState.Inherited;
default:
@@ -332,7 +312,7 @@ internal sealed class Window
/// <returns>Class name</returns>
private static string GetWindowClassName(IntPtr hwnd)
{
StringBuilder windowClassName = new StringBuilder(300);
var windowClassName = new StringBuilder(300);
var numCharactersWritten = NativeMethods.GetClassName(hwnd, windowClassName, windowClassName.MaxCapacity);
if (numCharactersWritten == 0)
@@ -350,16 +330,16 @@ internal sealed class Window
/// <returns>A new Instance of type <see cref="WindowProcess"/></returns>
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);
_handlesToProcessCache.Clear();
Debug.Print("Clearing Process Cache because it's size is " + HandlesToProcessCache.Count);
HandlesToProcessCache.Clear();
}
// Add window's process to cache if missing
if (!_handlesToProcessCache.ContainsKey(hWindow))
if (!HandlesToProcessCache.ContainsKey(hWindow))
{
// Get process ID and name
var processId = WindowProcess.GetProcessIDFromWindowHandle(hWindow);
@@ -368,23 +348,23 @@ internal sealed class Window
if (processName.Length != 0)
{
_handlesToProcessCache.Add(hWindow, new WindowProcess(processId, threadId, processName));
HandlesToProcessCache.Add(hWindow, new WindowProcess(processId, threadId, processName));
}
else
{
// 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}." });
_handlesToProcessCache.Add(hWindow, new WindowProcess(0, 0, string.Empty));
ExtensionHost.LogMessage(new LogMessage { Message = $"Invalid process {processId} ({processName}) for window handle {hWindow}." });
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'
// (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(() =>
{
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.
// (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);
// Update process info in cache
lock (_handlesToProcessCache)
lock (HandlesToProcessCache)
{
_handlesToProcessCache[hWindow].UpdateProcessInfo(childProcessId, childThreadId, childProcessName);
HandlesToProcessCache[hWindow].UpdateProcessInfo(childProcessId, childThreadId, childProcessName);
}
return false;
@@ -411,7 +391,7 @@ internal sealed class Window
}).Start();
}
return _handlesToProcessCache[hWindow];
return HandlesToProcessCache[hWindow];
}
}
}

View File

@@ -1,12 +1,9 @@
// 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.Linq;
using System.Text;
using Microsoft.CmdPal.Ext.WindowWalker.Commands;
using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
namespace Microsoft.CmdPal.Ext.WindowWalker.Components;
@@ -192,22 +189,27 @@ internal sealed class WindowProcess
/// <summary>
/// Gets the process name for the process ID
/// </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>
internal static string GetProcessNameFromProcessID(uint 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)
{
_ = Win32Helpers.CloseHandleIfNotNull(processHandle);
return processName.ToString().Split('\\').Reverse().ToArray()[0];
var processNameStr = processName.ToString();
var lastSeparatorIndex = processNameStr.LastIndexOf('\\');
return lastSeparatorIndex >= 0 ? processNameStr[(lastSeparatorIndex + 1)..] : processNameStr;
}
else
finally
{
_ = 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>
/// 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>
[ComImport]
[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.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
@@ -10,7 +9,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
/// <summary>
/// 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>
[GeneratedComInterface]
[Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")]

View File

@@ -2,9 +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;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
@@ -97,14 +95,6 @@ public static partial class NativeMethods
[DllImport("user32.dll")]
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)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool OpenProcessToken(SafeProcessHandle processHandle, TokenAccess desiredAccess, out SafeAccessTokenHandle tokenHandle);
@@ -265,113 +255,8 @@ public enum HRESULT : uint
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);
/// <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>
/// Options for DwmpActivateLivePreview
/// </summary>
@@ -655,16 +540,6 @@ public enum ProcessAccessFlags
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>
/// Contains information about the placement of a window on the screen.
/// </summary>
@@ -920,7 +795,7 @@ public struct POINT : IEquatable<POINT>
{
if (obj is POINT pt)
{
return this.X == pt.X && this.Y == pt.X;
return X == pt.X && Y == pt.X;
}
return false;
@@ -1145,22 +1020,6 @@ public enum ExtendedWindowStyles : uint
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
{
TokenIsAppContainer = 29,

View File

@@ -2,8 +2,6 @@
// 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;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
public static class OSVersionHelper
@@ -12,9 +10,4 @@ public static class OSVersionHelper
{
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.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;

View File

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

View File

@@ -2,16 +2,11 @@
// 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.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Text;
using ManagedCsWin32;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Win32;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
@@ -55,7 +50,7 @@ public class VirtualDesktopHelper
/// </summary>
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>
/// Initializes a new instance of the <see cref="VirtualDesktopHelper"/> class.
@@ -71,7 +66,7 @@ public class VirtualDesktopHelper
}
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;
}
@@ -97,33 +92,27 @@ public class VirtualDesktopHelper
var registryExplorerVirtualDesktops = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops"; // Windows 11
// 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)
{
var allDeskValue = (byte[]?)virtualDesktopKey.GetValue("VirtualDesktopIDs", null) ?? Array.Empty<byte>();
if (allDeskValue is not null)
{
// We clear only, if we can read from registry. Otherwise, we keep the existing values.
_availableDesktops.Clear();
var allDeskValue = (byte[]?)virtualDesktopKey.GetValue("VirtualDesktopIDs", null) ?? [];
// Each guid has a length of 16 elements
var numberOfDesktops = allDeskValue.Length / 16;
for (var i = 0; i < numberOfDesktops; i++)
{
var guidArray = new byte[16];
Array.ConstrainedCopy(allDeskValue, i * 16, guidArray, 0, 16);
_availableDesktops.Add(new Guid(guidArray));
}
}
else
// 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
var numberOfDesktops = allDeskValue.Length / 16;
for (var i = 0; i < numberOfDesktops; i++)
{
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
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)
{
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.
// 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;
}
}
@@ -166,8 +155,8 @@ public class VirtualDesktopHelper
UpdateDesktopList();
}
List<VDesktop> list = new List<VDesktop>();
foreach (Guid d in _availableDesktops)
var list = new List<VDesktop>();
foreach (var d in _availableDesktops)
{
list.Add(CreateVDesktopInstance(d));
}
@@ -257,7 +246,7 @@ public class VirtualDesktopHelper
{
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;
}
@@ -265,7 +254,7 @@ public class VirtualDesktopHelper
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) + "}";
using RegistryKey? deskSubKey = Registry.CurrentUser.OpenSubKey(registryPath, false);
using var deskSubKey = Registry.CurrentUser.OpenSubKey(registryPath, false);
var desktopName = deskSubKey?.GetValue("Name");
return (desktopName is not null) ? (string)desktopName : defaultName;
@@ -275,7 +264,7 @@ public class VirtualDesktopHelper
/// Returns the position type for a desktop.
/// </summary>
/// <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)
{
var desktopNumber = GetDesktopNumber(desktop);
@@ -315,7 +304,7 @@ public class VirtualDesktopHelper
{
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;
return unchecked((int)HRESULT.E_UNEXPECTED);
}
@@ -332,11 +321,11 @@ public class VirtualDesktopHelper
{
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);
}
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);
}
@@ -350,12 +339,12 @@ public class VirtualDesktopHelper
{
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;
}
_ = _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;
if (hResult != (int)HRESULT.S_OK)
@@ -417,14 +406,14 @@ public class VirtualDesktopHelper
{
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;
}
var hr = _virtualDesktopManager.MoveWindowToDesktop(hWindow, ref desktopId);
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;
}
@@ -438,27 +427,27 @@ public class VirtualDesktopHelper
/// <returns><see langword="True"/> on success and <see langword="false"/> on failure.</returns>
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)
{
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;
}
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;
}
var windowDesktopNumber = GetDesktopIdList().IndexOf(windowDesktop);
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;
}
Guid newDesktop = _availableDesktops[windowDesktopNumber - 1];
var newDesktop = _availableDesktops[windowDesktopNumber - 1];
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>
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)
{
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;
}
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;
}
var windowDesktopNumber = GetDesktopIdList().IndexOf(windowDesktop);
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;
}
Guid newDesktop = _availableDesktops[windowDesktopNumber + 1];
var newDesktop = _availableDesktops[windowDesktopNumber + 1];
return MoveWindowToDesktop(hWindow, ref newDesktop);
}
@@ -507,11 +496,11 @@ public class VirtualDesktopHelper
}
// 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 isDesktopVisible = (hWindow != default) ? (isAllDesktops || desktopType == VirtualDesktopAssignmentType.CurrentDesktop) : IsDesktopVisible(desktop);
return new VDesktop()
return new VDesktop
{
Id = 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.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
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>
/// Returns the last Win32 Error code thrown by a native method if enabled for this method.
/// </summary>
@@ -44,14 +32,4 @@ public static class Win32Helpers
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.
// See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions.Toolkit;
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 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
}

View File

@@ -2,26 +2,18 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.WindowWalker.Commands;
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
{
private readonly Window? _window;
public Window? Window => _window;
public Window? Window { get; }
public WindowWalkerListItem(Window? 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.
// See the LICENSE file in the project root for more information.
using System;
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.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker.Pages;
@@ -41,8 +37,8 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
{
ArgumentNullException.ThrowIfNull(query);
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
_cancellationTokenSource = new System.Threading.CancellationTokenSource();
WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.UpdateDesktopList();
@@ -54,7 +50,7 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
{
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];
@@ -73,7 +69,7 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
private static int ScoreFunction(string q, Window window)
{
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);
}
@@ -91,7 +87,7 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
{
if (disposing)
{
_cancellationTokenSource?.Dispose();
_cancellationTokenSource.Dispose();
_disposed = true;
}
}

View File

@@ -2,11 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// 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.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.WindowWalker;