Adding FxCop to Microsoft.Plugin.WindowWalker (#6260)

* Adding FxCop to Microsoft.Plugin.WindowWalker

* Delete WindowResult.cs -- Fix for CA1812 WindowResult is an internal class that is apparently never instantiated. If so, remove the code from the assembly. If this class is intended to contain only static members, make it static (Shared in Visual Basic).

* Fix for CA1806 UpdateOpenWindowsList calls EnumWindows but does not use the HRESULT or error code that the method returns. This could lead to unexpected behavior in error conditions or low-resource situations. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method.

* Fix for: CA1066 Type Microsoft.Plugin.WindowWalker.Components.InteropAndHelpers.RECT should implement IEquatable<T> because it overrides Equals

* Fix for:  CA1052 Type 'FuzzyMatching' is a static holder type but is neither static nor NotInheritable

* Suppress for CA1069 - These values are defined in
https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles.

CA1069 The enum member 'WS_EX_LTRREADING' has the same constant value '0' as member 'WS_EX_LEFT'
CA1069 The enum member 'WS_EX_RIGHTSCROLLBAR' has the same constant value '0' as member 'WS_EX_LEFT'

* Supress CA1069

Code Description
CA1069 The enum member 'SWP_NOREPOSITION' has the same constant value '512' as member 'SWP_NOOWNERZORDER'
CA1069 The enum member 'SWP_FRAMECHANGED' has the same constant value '32' as member 'SWP_DRAWFRAME'

* Suprress CA1069 for ShowWindow values.  See

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow

CA1069 The enum member 'ShowMaximized' has the same constant value '3' as member 'Maximize'

* Fix code formatting error

* Fix for CA2235: Making POINT serializable

CA2235 Field MinPosition is a member of type WINDOWPLACEMENT which is serializable but is of type Microsoft.Plugin.WindowWalker.Components.InteropAndHelpers.POINT which is not serializable
CA2235 Field MaxPosition is a member of type WINDOWPLACEMENT which is serializable but is of type Microsoft.Plugin.WindowWalker.Components.InteropAndHelpers.POINT which is not serializable

* Fix CA2235 Making RECT serializable

CA2235 Field NormalPosition is a member of type WINDOWPLACEMENT which is serializable but is of type Microsoft.Plugin.WindowWalker.Components.InteropAndHelpers.RECT which is not serializable

* Fixes for CA2101 Specify marshaling for P/Invoke string arguments.

* Fixes for CA2007 Consider calling ConfigureAwait on the awaited task

* Fixes for the following (CA1822 / CA1801):
CA1822 Member 'OnOpenWindowsUpdate' does not access instance data and can be marked as static
Code Description
CA1801 Parameter value of method add_OnOpenWindowsUpdate is never used. Remove the parameter or use it in the method body.
CA1801 Parameter value of method remove_OnOpenWindowsUpdate is never used. Remove the parameter or use it in the method body.

* Fix: CA1710 Rename OpenWindowsUpdateHandler to end in 'EventHandler'

* Fix CA1822 Member 'GetProcessIDFromWindowHandle' does not access instance data and can be marked as static

* Fix CA1062 In externally visible method 'List<int> FuzzyMatching.FindBestFuzzyMatch(string text, string searchText)', validate parameter 'searchText' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.

* Fixes for CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings.

CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'FuzzyMatching.FindBestFuzzyMatch(string, string)' with a call to 'string.ToLower(CultureInfo)'.

Code Description
CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'FuzzyMatching.FindBestFuzzyMatch(string, string)' with a call to 'string.ToLower(CultureInfo)'.

* Supressing warning for CA1814: Prefer jagged arrays over multidimensional however this might be something to consider if needing to optimize the window walker search.

* Fix: CA1062 In externally visible method 'List<List<int>> FuzzyMatching.GetAllMatchIndexes(bool[,] matches)', validate parameter 'matches' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.

* Fix for CA1062 In externally visible method 'int FuzzyMatching.CalculateScoreForMatches(List<int> matches)', validate parameter 'matches' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.

* Fixes for CA1806 Calls x...  but does not use the HRESULT or error code that the method returns. This could lead to unexpected behavior in error conditions or low-resource situations. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method.

Using discard for methods that return void, and checking the hresult before returning parameters.

* Fix for CA1820 Test for empty strings using 'string.Length' property or 'string.IsNullOrEmpty' method instead of an Equality check

* Supress CA1031 Modify 'get_WindowIcon' to catch a more specific allowed exception type, or rethrow the exception

* Code Description
CA1062 In externally visible method 'List<Result> Main.Query(Query query)', validate parameter 'query' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.

* Fixes For CA1304 The behavior of 'string.ToUpper()' could vary based on the current user's locale settings.

CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'SearchController.SearchText.set' with a call to 'string.ToLower(CultureInfo)'.
CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'Window.ProcessName.get' with a call to 'string.ToLower(CultureInfo)'.
CA1304 The behavior of 'string.ToLower()' could vary based on the current user's locale settings. Replace this call in 'Window.SwitchToWindow()' with a call to 'string.ToLower(CultureInfo)'.
CA1304 The behavior of 'string.ToUpper()' could vary based on the current user's locale settings. Replace this call in 'Window.ToString()' with a call to 'string.ToUpper(CultureInfo)'.
CA1307 The behavior of 'string.Equals(string?)' could vary based on the current user's locale settings. Replace this call in 'Microsoft.Plugin.WindowWalker.Components.Window.SwitchToWindow()' with a call to 'string.Equals(string?, System.StringComparison)'.

* Fix: CA1710 Rename SearchResultUpdateHandler to end in 'EventHandler'

* Fix CA1060 Move pinvokes to native methods class

* Fix: CS0067 The event 'OpenWindows.OnOpenWindowsUpdateEventHandler' is never used

1) Remove SearchController::OpenWindowsUpdateHandler(object sender, SearchResultUpdateEventArgs e) as it wasn't being called and was redundant with Update Search Text.
2) In Main.cs calling UpdateOpenWindowsList before UpdateSearchText so that the latest enumerated windows will be called.
3) Removing unused OnOpenWindowsUpdateEventHandler and related code.

* Revert "Fixes for CA2101 Specify marshaling for P/Invoke string arguments."

This reverts commit b3dfe07915.

* Fixing CA2101 by turning off best fit mapping for methods that require ANSI marshalling.

See: https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2101?view=vs-2019

* Previous fix for CA1806 misunderstood int result as hresult.  The actual return value is number of characters written.
NativeMethods.GetWindowText(hwnd, titleBuffer, sizeOfTitle);

* Previous fix for CA1806 misunderstood int result as hresult.  The actual return value is number of characters written.

NativeMethods.GetClassName(Hwnd, windowClassName, windowClassName.MaxCapacity);

* Removing unused window code.  This was done instead of validating fxcop changes in WindowIcon.

* Fixing typos in Window.cs (charachter -> character)
This commit is contained in:
ryanbodrug-microsoft
2020-09-10 09:44:22 -07:00
committed by GitHub
parent efd5c33a92
commit c4cb3df306
9 changed files with 108 additions and 177 deletions

View File

@@ -3,7 +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.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
namespace Microsoft.Plugin.WindowWalker.Components namespace Microsoft.Plugin.WindowWalker.Components
@@ -11,7 +13,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <summary> /// <summary>
/// Class housing fuzzy matching methods /// Class housing fuzzy matching methods
/// </summary> /// </summary>
public class FuzzyMatching public static class FuzzyMatching
{ {
/// <summary> /// <summary>
/// Finds the best match (the one with the most /// Finds the best match (the one with the most
@@ -22,10 +24,21 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <param name="text">The text to search inside of</param> /// <param name="text">The text to search inside of</param>
/// <param name="searchText">the text to search for</param> /// <param name="searchText">the text to search for</param>
/// <returns>returns the index location of each of the letters of the matches</returns> /// <returns>returns the index location of each of the letters of the matches</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1814:Prefer jagged arrays over multidimensional", Justification = "matches does not waste space with the current implementation, however this could probably be optimized to store the indices of matches instead of boolean values. Currently there are no unit tests for this, but we could refactor if memory/perf becomes an issue. ")]
public static List<int> FindBestFuzzyMatch(string text, string searchText) public static List<int> FindBestFuzzyMatch(string text, string searchText)
{ {
searchText = searchText.ToLower(); if (searchText == null)
text = text.ToLower(); {
throw new ArgumentNullException(nameof(searchText));
}
if (text == null)
{
throw new ArgumentNullException(nameof(text));
}
searchText = searchText.ToLower(CultureInfo.CurrentCulture);
text = text.ToLower(CultureInfo.CurrentCulture);
// Create a grid to march matches like // Create a grid to march matches like
// eg. // eg.
@@ -71,8 +84,14 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// a two dimensional array with the first dimension the text and the second /// a two dimensional array with the first dimension the text and the second
/// one the search string and each cell marked as an intersection between the two</param> /// one the search string and each cell marked as an intersection between the two</param>
/// <returns>a list of the possible combinations that match the search text</returns> /// <returns>a list of the possible combinations that match the search text</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1814:Prefer jagged arrays over multidimensional", Justification = "matches does not waste space with the current implementation, however this could probably be optimized to store the indices of matches instead of boolean values. Currently there are no unit tests for this, but we could refactor if memory/perf becomes an issue. ")]
public static List<List<int>> GetAllMatchIndexes(bool[,] matches) public static List<List<int>> GetAllMatchIndexes(bool[,] matches)
{ {
if (matches == null)
{
throw new ArgumentNullException(nameof(matches));
}
List<List<int>> results = new List<List<int>>(); List<List<int>> results = new List<List<int>>();
for (int secondIndex = 0; secondIndex < matches.GetLength(1); secondIndex++) for (int secondIndex = 0; secondIndex < matches.GetLength(1); secondIndex++)
@@ -109,6 +128,11 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <returns>an integer representing the score</returns> /// <returns>an integer representing the score</returns>
public static int CalculateScoreForMatches(List<int> matches) public static int CalculateScoreForMatches(List<int> matches)
{ {
if (matches == null)
{
throw new ArgumentNullException(nameof(matches));
}
var score = 0; var score = 0;
for (int currentIndex = 1; currentIndex < matches.Count; currentIndex++) for (int currentIndex = 1; currentIndex < matches.Count; currentIndex++)

View File

@@ -18,9 +18,9 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <param name="hwnd">handle to the window to exclude</param> /// <param name="hwnd">handle to the window to exclude</param>
public static void SetWindowExclusionFromLivePreview(IntPtr hwnd) public static void SetWindowExclusionFromLivePreview(IntPtr hwnd)
{ {
int renderPolicy = (int)InteropAndHelpers.DwmNCRenderingPolicy.Enabled; int renderPolicy = (int)NativeMethods.DwmNCRenderingPolicy.Enabled;
InteropAndHelpers.DwmSetWindowAttribute( _ = NativeMethods.DwmSetWindowAttribute(
hwnd, hwnd,
12, 12,
ref renderPolicy, ref renderPolicy,
@@ -34,11 +34,11 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <param name="windowToSpare">the window which should not be transparent but is not the target window</param> /// <param name="windowToSpare">the window which should not be transparent but is not the target window</param>
public static void ActivateLivePreview(IntPtr targetWindow, IntPtr windowToSpare) public static void ActivateLivePreview(IntPtr targetWindow, IntPtr windowToSpare)
{ {
InteropAndHelpers.DwmpActivateLivePreview( _ = NativeMethods.DwmpActivateLivePreview(
true, true,
targetWindow, targetWindow,
windowToSpare, windowToSpare,
InteropAndHelpers.LivePreviewTrigger.Superbar, NativeMethods.LivePreviewTrigger.Superbar,
IntPtr.Zero); IntPtr.Zero);
} }
@@ -47,11 +47,11 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// </summary> /// </summary>
public static void DeactivateLivePreview() public static void DeactivateLivePreview()
{ {
InteropAndHelpers.DwmpActivateLivePreview( _ = NativeMethods.DwmpActivateLivePreview(
false, false,
IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero,
InteropAndHelpers.LivePreviewTrigger.AltTab, NativeMethods.LivePreviewTrigger.AltTab,
IntPtr.Zero); IntPtr.Zero);
} }
} }

View File

@@ -12,7 +12,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <summary> /// <summary>
/// Interop calls with helper layers /// Interop calls with helper layers
/// </summary> /// </summary>
internal class InteropAndHelpers internal class NativeMethods
{ {
public delegate bool CallBackPtr(IntPtr hwnd, IntPtr lParam); public delegate bool CallBackPtr(IntPtr hwnd, IntPtr lParam);
@@ -20,6 +20,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// Some flags for interop calls to SetWindowPosition /// Some flags for interop calls to SetWindowPosition
/// </summary> /// </summary>
[Flags] [Flags]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1069:Enums values should not be duplicated", Justification = "These are defined in win32 libraries. See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos")]
public enum SetWindowPosFlags : uint public enum SetWindowPosFlags : uint
{ {
/// <summary> /// <summary>
@@ -150,6 +151,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <summary> /// <summary>
/// Show Window Enums /// Show Window Enums
/// </summary> /// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1069:Enums values should not be duplicated", Justification = "This is defined in the ShowWindow win32 method. See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow")]
public enum ShowWindowCommands public enum ShowWindowCommands
{ {
/// <summary> /// <summary>
@@ -425,8 +427,9 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <summary> /// <summary>
/// Required pointless variables that we don't use in making a windows show /// Required pointless variables that we don't use in making a windows show
/// </summary> /// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct RECT public struct RECT : IEquatable<RECT>
{ {
public int Left; public int Left;
public int Top; public int Top;
@@ -567,6 +570,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <summary> /// <summary>
/// Same as the RECT struct above /// Same as the RECT struct above
/// </summary> /// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct POINT public struct POINT
{ {
@@ -647,6 +651,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// The following are the extended window styles /// The following are the extended window styles
/// </summary> /// </summary>
[Flags] [Flags]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1069:Enums values should not be duplicated", Justification = "These values are specific in the win32 libraries. See https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles")]
public enum ExtendedWindowStyles : uint public enum ExtendedWindowStyles : uint
{ {
/// <summary> /// <summary>
@@ -847,10 +852,10 @@ namespace Microsoft.Plugin.WindowWalker.Components
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("psapi.dll")] [DllImport("psapi.dll", BestFitMapping = false)]
public static extern uint GetProcessImageFileName(IntPtr hProcess, [Out] StringBuilder lpImageFileName, [In][MarshalAs(UnmanagedType.U4)] int nSize); public static extern uint GetProcessImageFileName(IntPtr hProcess, [Out] StringBuilder lpImageFileName, [In][MarshalAs(UnmanagedType.U4)] int nSize);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true, BestFitMapping = false)]
public static extern IntPtr GetProp(IntPtr hWnd, string lpString); public static extern IntPtr GetProp(IntPtr hWnd, string lpString);
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
@@ -865,7 +870,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
[DllImport("dwmapi.dll", PreserveSig = false)] [DllImport("dwmapi.dll", PreserveSig = false)]
public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out int pvAttribute, int cbAttribute); public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out int pvAttribute, int cbAttribute);
[DllImport("user32.dll")] [DllImport("user32.dll", BestFitMapping = false)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]

View File

@@ -16,16 +16,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <summary> /// <summary>
/// Delegate handler for open windows updates /// Delegate handler for open windows updates
/// </summary> /// </summary>
public delegate void OpenWindowsUpdateHandler(object sender, SearchController.SearchResultUpdateEventArgs e); public delegate void OpenWindowsUpdateEventHandler(object sender, SearchController.SearchResultUpdateEventArgs e);
/// <summary>
/// Event raised when there is an update to the list of open windows
/// </summary>
public event OpenWindowsUpdateHandler OnOpenWindowsUpdate
{
add { }
remove { }
}
/// <summary> /// <summary>
/// List of all the open windows /// List of all the open windows
@@ -78,8 +69,8 @@ namespace Microsoft.Plugin.WindowWalker.Components
public void UpdateOpenWindowsList() public void UpdateOpenWindowsList()
{ {
windows.Clear(); windows.Clear();
InteropAndHelpers.CallBackPtr callbackptr = new InteropAndHelpers.CallBackPtr(WindowEnumerationCallBack); NativeMethods.CallBackPtr callbackptr = new NativeMethods.CallBackPtr(WindowEnumerationCallBack);
InteropAndHelpers.EnumWindows(callbackptr, 0); _ = NativeMethods.EnumWindows(callbackptr, 0);
} }
/// <summary> /// <summary>

View File

@@ -5,6 +5,7 @@
// 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -34,12 +35,12 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <summary> /// <summary>
/// Delegate handler for open windows updates /// Delegate handler for open windows updates
/// </summary> /// </summary>
public delegate void SearchResultUpdateHandler(object sender, SearchResultUpdateEventArgs e); public delegate void SearchResultUpdateEventHandler(object sender, SearchResultUpdateEventArgs e);
/// <summary> /// <summary>
/// Event raised when there is an update to the list of open windows /// Event raised when there is an update to the list of open windows
/// </summary> /// </summary>
public event SearchResultUpdateHandler OnSearchResultUpdate; public event SearchResultUpdateEventHandler OnSearchResultUpdateEventHandler;
/// <summary> /// <summary>
/// Gets or sets the current search text /// Gets or sets the current search text
@@ -53,7 +54,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
set set
{ {
searchText = value.ToLower().Trim(); searchText = value.ToLower(CultureInfo.CurrentCulture).Trim();
} }
} }
@@ -88,7 +89,6 @@ namespace Microsoft.Plugin.WindowWalker.Components
private SearchController() private SearchController()
{ {
searchText = string.Empty; searchText = string.Empty;
OpenWindows.Instance.OnOpenWindowsUpdate += OpenWindowsUpdateHandler;
} }
/// <summary> /// <summary>
@@ -97,17 +97,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
public async Task UpdateSearchText(string searchText) public async Task UpdateSearchText(string searchText)
{ {
SearchText = searchText; SearchText = searchText;
await SyncOpenWindowsWithModelAsync(); await SyncOpenWindowsWithModelAsync().ConfigureAwait(false);
}
/// <summary>
/// Event handler called when the OpenWindows list changes
/// </summary>
/// <param name="sender">sending item</param>
/// <param name="e">event arg</param>
public async void OpenWindowsUpdateHandler(object sender, SearchResultUpdateEventArgs e)
{
await SyncOpenWindowsWithModelAsync();
} }
/// <summary> /// <summary>
@@ -119,16 +109,16 @@ namespace Microsoft.Plugin.WindowWalker.Components
List<Window> snapshotOfOpenWindows = OpenWindows.Instance.Windows; List<Window> snapshotOfOpenWindows = OpenWindows.Instance.Windows;
if (SearchText == string.Empty) if (string.IsNullOrWhiteSpace(SearchText))
{ {
searchMatches = new List<SearchResult>(); searchMatches = new List<SearchResult>();
} }
else else
{ {
searchMatches = await FuzzySearchOpenWindowsAsync(snapshotOfOpenWindows); searchMatches = await FuzzySearchOpenWindowsAsync(snapshotOfOpenWindows).ConfigureAwait(false);
} }
OnSearchResultUpdate?.Invoke(this, new SearchResultUpdateEventArgs()); OnSearchResultUpdateEventHandler?.Invoke(this, new SearchResultUpdateEventArgs());
} }
/// <summary> /// <summary>

View File

@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -33,12 +34,6 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// </summary> /// </summary>
private static readonly Dictionary<IntPtr, string> _handlesToProcessCache = new Dictionary<IntPtr, string>(); private static readonly Dictionary<IntPtr, string> _handlesToProcessCache = new Dictionary<IntPtr, string>();
/// <summary>
/// The list of icons from process so that we don't have to keep
/// loading them from disk
/// </summary>
private static readonly Dictionary<uint, ImageSource> _processIdsToIconsCache = new Dictionary<uint, ImageSource>();
/// <summary> /// <summary>
/// The handle to the window /// The handle to the window
/// </summary> /// </summary>
@@ -51,11 +46,16 @@ namespace Microsoft.Plugin.WindowWalker.Components
{ {
get get
{ {
int sizeOfTitle = InteropAndHelpers.GetWindowTextLength(hwnd); int sizeOfTitle = NativeMethods.GetWindowTextLength(hwnd);
if (sizeOfTitle++ > 0) if (sizeOfTitle++ > 0)
{ {
StringBuilder titleBuffer = new StringBuilder(sizeOfTitle); StringBuilder titleBuffer = new StringBuilder(sizeOfTitle);
InteropAndHelpers.GetWindowText(hwnd, titleBuffer, sizeOfTitle); var numCharactersWritten = NativeMethods.GetWindowText(hwnd, titleBuffer, sizeOfTitle);
if (numCharactersWritten == 0)
{
return string.Empty;
}
return titleBuffer.ToString(); return titleBuffer.ToString();
} }
else else
@@ -106,11 +106,11 @@ namespace Microsoft.Plugin.WindowWalker.Components
} }
} }
if (_handlesToProcessCache[hwnd].ToLower() == "applicationframehost.exe") if (_handlesToProcessCache[hwnd].ToUpperInvariant() == "APPLICATIONFRAMEHOST.EXE")
{ {
new Task(() => new Task(() =>
{ {
InteropAndHelpers.CallBackPtr callbackptr = new InteropAndHelpers.CallBackPtr((IntPtr hwnd, IntPtr lParam) => NativeMethods.CallBackPtr callbackptr = new NativeMethods.CallBackPtr((IntPtr hwnd, IntPtr lParam) =>
{ {
var childProcessId = GetProcessIDFromWindowHandle(hwnd); var childProcessId = GetProcessIDFromWindowHandle(hwnd);
if (childProcessId != ProcessID) if (childProcessId != ProcessID)
@@ -123,7 +123,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
return true; return true;
} }
}); });
InteropAndHelpers.EnumChildWindows(Hwnd, callbackptr, 0); _ = NativeMethods.EnumChildWindows(Hwnd, callbackptr, 0);
}).Start(); }).Start();
} }
@@ -140,46 +140,17 @@ namespace Microsoft.Plugin.WindowWalker.Components
get get
{ {
StringBuilder windowClassName = new StringBuilder(300); StringBuilder windowClassName = new StringBuilder(300);
InteropAndHelpers.GetClassName(Hwnd, windowClassName, windowClassName.MaxCapacity); var numCharactersWritten = NativeMethods.GetClassName(Hwnd, windowClassName, windowClassName.MaxCapacity);
if (numCharactersWritten == 0)
{
return string.Empty;
}
return windowClassName.ToString(); return windowClassName.ToString();
} }
} }
/// <summary>
/// Gets represents the Window Icon for the specified window
/// </summary>
public ImageSource WindowIcon
{
get
{
lock (_processIdsToIconsCache)
{
InteropAndHelpers.GetWindowThreadProcessId(Hwnd, out uint processId);
if (!_processIdsToIconsCache.ContainsKey(processId))
{
try
{
Process process = Process.GetProcessById((int)processId);
Icon tempIcon = Icon.ExtractAssociatedIcon(process.Modules[0].FileName);
_processIdsToIconsCache.Add(processId, Imaging.CreateBitmapSourceFromHIcon(
tempIcon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()));
}
catch
{
BitmapImage failedImage = new BitmapImage(new Uri(@"Images\failedIcon.jpg", UriKind.Relative));
_processIdsToIconsCache.Add(processId, failedImage);
}
}
return _processIdsToIconsCache[processId];
}
}
}
/// <summary> /// <summary>
/// Gets a value indicating whether is the window visible (might return false if it is a hidden IE tab) /// Gets a value indicating whether is the window visible (might return false if it is a hidden IE tab)
/// </summary> /// </summary>
@@ -187,7 +158,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
{ {
get get
{ {
return InteropAndHelpers.IsWindowVisible(Hwnd); return NativeMethods.IsWindowVisible(Hwnd);
} }
} }
@@ -198,7 +169,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
{ {
get get
{ {
return InteropAndHelpers.IsWindow(Hwnd); return NativeMethods.IsWindow(Hwnd);
} }
} }
@@ -209,9 +180,9 @@ namespace Microsoft.Plugin.WindowWalker.Components
{ {
get get
{ {
return (InteropAndHelpers.GetWindowLong(Hwnd, InteropAndHelpers.GWL_EXSTYLE) & return (NativeMethods.GetWindowLong(Hwnd, NativeMethods.GWL_EXSTYLE) &
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_TOOLWINDOW) == (uint)NativeMethods.ExtendedWindowStyles.WS_EX_TOOLWINDOW) ==
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_TOOLWINDOW; (uint)NativeMethods.ExtendedWindowStyles.WS_EX_TOOLWINDOW;
} }
} }
@@ -222,9 +193,9 @@ namespace Microsoft.Plugin.WindowWalker.Components
{ {
get get
{ {
return (InteropAndHelpers.GetWindowLong(Hwnd, InteropAndHelpers.GWL_EXSTYLE) & return (NativeMethods.GetWindowLong(Hwnd, NativeMethods.GWL_EXSTYLE) &
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_APPWINDOW) == (uint)NativeMethods.ExtendedWindowStyles.WS_EX_APPWINDOW) ==
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_APPWINDOW; (uint)NativeMethods.ExtendedWindowStyles.WS_EX_APPWINDOW;
} }
} }
@@ -235,18 +206,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
{ {
get get
{ {
return InteropAndHelpers.GetProp(Hwnd, "ITaskList_Deleted") != IntPtr.Zero; return NativeMethods.GetProp(Hwnd, "ITaskList_Deleted") != IntPtr.Zero;
}
}
/// <summary>
/// Gets a value indicating whether get a value indicating whether the app is a cloaked UWP app
/// </summary>
public bool IsUWPCloaked
{
get
{
return IsWindowCloaked() && ClassName == "ApplicationFrameWindow";
} }
} }
@@ -257,21 +217,10 @@ namespace Microsoft.Plugin.WindowWalker.Components
{ {
get get
{ {
return InteropAndHelpers.GetWindow(Hwnd, InteropAndHelpers.GetWindowCmd.GW_OWNER) != null; return NativeMethods.GetWindow(Hwnd, NativeMethods.GetWindowCmd.GW_OWNER) != null;
} }
} }
/// <summary>
/// Gets a value indicating whether is the window cloaked. To detect UWP apps in background or win32 apps running in another virtual desktop
/// </summary>
public bool IsWindowCloaked()
{
int isCloaked = 0;
const int DWMWA_CLOAKED = 14;
InteropAndHelpers.DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, out isCloaked, sizeof(int));
return isCloaked != 0;
}
/// <summary> /// <summary>
/// Gets a value indicating whether returns true if the window is minimized /// Gets a value indicating whether returns true if the window is minimized
/// </summary> /// </summary>
@@ -294,14 +243,6 @@ namespace Microsoft.Plugin.WindowWalker.Components
this.hwnd = hwnd; this.hwnd = hwnd;
} }
/// <summary>
/// Highlights a window to help the user identify the window that has been selected
/// </summary>
public void HighlightWindow()
{
throw new NotImplementedException();
}
/// <summary> /// <summary>
/// Switches desktop focus to the window /// Switches desktop focus to the window
/// </summary> /// </summary>
@@ -311,16 +252,16 @@ namespace Microsoft.Plugin.WindowWalker.Components
// 1) There is a weird flashing behavior when trying // 1) There is a weird flashing behavior when trying
// 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
if (ProcessName.ToLower().Equals("iexplore.exe") || !Minimized) if (ProcessName.ToUpperInvariant().Equals("IEXPLORE.EXE", StringComparison.Ordinal) || !Minimized)
{ {
InteropAndHelpers.SetForegroundWindow(Hwnd); NativeMethods.SetForegroundWindow(Hwnd);
} }
else else
{ {
InteropAndHelpers.ShowWindow(Hwnd, InteropAndHelpers.ShowWindowCommands.Restore); NativeMethods.ShowWindow(Hwnd, NativeMethods.ShowWindowCommands.Restore);
} }
InteropAndHelpers.FlashWindow(Hwnd, true); NativeMethods.FlashWindow(Hwnd, true);
} }
/// <summary> /// <summary>
@@ -329,7 +270,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <returns>The title of the window</returns> /// <returns>The title of the window</returns>
public override string ToString() public override string ToString()
{ {
return Title + " (" + ProcessName.ToUpper() + ")"; return Title + " (" + ProcessName.ToUpper(CultureInfo.CurrentCulture) + ")";
} }
/// <summary> /// <summary>
@@ -338,16 +279,16 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <returns>The state (minimized, maximized, etc..) of the window</returns> /// <returns>The state (minimized, maximized, etc..) of the window</returns>
public WindowSizeState GetWindowSizeState() public WindowSizeState GetWindowSizeState()
{ {
InteropAndHelpers.GetWindowPlacement(Hwnd, out InteropAndHelpers.WINDOWPLACEMENT placement); NativeMethods.GetWindowPlacement(Hwnd, out NativeMethods.WINDOWPLACEMENT placement);
switch (placement.ShowCmd) switch (placement.ShowCmd)
{ {
case InteropAndHelpers.ShowWindowCommands.Normal: case NativeMethods.ShowWindowCommands.Normal:
return WindowSizeState.Normal; return WindowSizeState.Normal;
case InteropAndHelpers.ShowWindowCommands.Minimize: case NativeMethods.ShowWindowCommands.Minimize:
case InteropAndHelpers.ShowWindowCommands.ShowMinimized: case NativeMethods.ShowWindowCommands.ShowMinimized:
return WindowSizeState.Minimized; return WindowSizeState.Minimized;
case InteropAndHelpers.ShowWindowCommands.Maximize: // No need for ShowMaximized here since its also of value 3 case NativeMethods.ShowWindowCommands.Maximize: // No need for ShowMaximized here since its also of value 3
return WindowSizeState.Maximized; return WindowSizeState.Maximized;
default: default:
// throw new Exception("Don't know how to handle window state = " + placement.ShowCmd); // throw new Exception("Don't know how to handle window state = " + placement.ShowCmd);
@@ -375,10 +316,10 @@ namespace Microsoft.Plugin.WindowWalker.Components
{ {
uint processId = GetProcessIDFromWindowHandle(hwnd); uint processId = GetProcessIDFromWindowHandle(hwnd);
ProcessID = processId; ProcessID = processId;
IntPtr processHandle = InteropAndHelpers.OpenProcess(InteropAndHelpers.ProcessAccessFlags.AllAccess, true, (int)processId); IntPtr processHandle = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.AllAccess, true, (int)processId);
StringBuilder processName = new StringBuilder(MaximumFileNameLength); StringBuilder processName = new StringBuilder(MaximumFileNameLength);
if (InteropAndHelpers.GetProcessImageFileName(processHandle, processName, MaximumFileNameLength) != 0) if (NativeMethods.GetProcessImageFileName(processHandle, processName, MaximumFileNameLength) != 0)
{ {
return processName.ToString().Split('\\').Reverse().ToArray()[0]; return processName.ToString().Split('\\').Reverse().ToArray()[0];
} }
@@ -393,9 +334,9 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// </summary> /// </summary>
/// <param name="hwnd">The handle to the window</param> /// <param name="hwnd">The handle to the window</param>
/// <returns>The process ID</returns> /// <returns>The process ID</returns>
private uint GetProcessIDFromWindowHandle(IntPtr hwnd) private static uint GetProcessIDFromWindowHandle(IntPtr hwnd)
{ {
InteropAndHelpers.GetWindowThreadProcessId(hwnd, out uint processId); _ = NativeMethods.GetWindowThreadProcessId(hwnd, out uint processId);
return processId; return processId;
} }
} }

View File

@@ -1,31 +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.
namespace Microsoft.Plugin.WindowWalker.Components
{
internal class WindowResult : Window
{
/// <summary>
/// Number of letters in between constant for when
/// the result hasn't been set yet
/// </summary>
public const int NoResult = -1;
/// <summary>
/// Gets or sets properties that signify how many characters (including spaces)
/// were found when matching the results
/// </summary>
public int LettersInBetweenScore { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="WindowResult"/> class.
/// Constructor for WindowResult
/// </summary>
public WindowResult(Window window)
: base(window.Hwnd)
{
LettersInBetweenScore = NoResult;
}
}
}

View File

@@ -2,6 +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.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.Plugin.WindowWalker.Components; using Microsoft.Plugin.WindowWalker.Components;
@@ -19,14 +20,20 @@ namespace Microsoft.Plugin.WindowWalker
static Main() static Main()
{ {
SearchController.Instance.OnSearchResultUpdate += SearchResultUpdated; SearchController.Instance.OnSearchResultUpdateEventHandler += SearchResultUpdated;
OpenWindows.Instance.UpdateOpenWindowsList(); OpenWindows.Instance.UpdateOpenWindowsList();
} }
public List<Result> Query(Query query) public List<Result> Query(Query query)
{ {
SearchController.Instance.UpdateSearchText(query.RawQuery).Wait(); if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
OpenWindows.Instance.UpdateOpenWindowsList(); OpenWindows.Instance.UpdateOpenWindowsList();
SearchController.Instance.UpdateSearchText(query.RawQuery).Wait();
return _results.Select(x => new Result() return _results.Select(x => new Result()
{ {
Title = x.Result.Title, Title = x.Result.Title,

View File

@@ -66,6 +66,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" /> <PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Runtime" Version="4.3.1" /> <PackageReference Include="System.Runtime" Version="4.3.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>