Files
PowerToys/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Registry/Helper/RegistryHelper.cs
Davide Giacometti 6d138e80fb [Analyzers] Update StyleCop and enable SA1200 (#22707)
* update StyleCop and enable SA1200

* Fix merge issues

* fix build and added using rule
2022-12-18 13:27:14 +00:00

232 lines
9.1 KiB
C#

// 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.Collections.ObjectModel;
using System.Linq;
using Microsoft.PowerToys.Run.Plugin.Registry.Classes;
using Microsoft.PowerToys.Run.Plugin.Registry.Constants;
using Microsoft.PowerToys.Run.Plugin.Registry.Properties;
using Microsoft.Win32;
namespace Microsoft.PowerToys.Run.Plugin.Registry.Helper
{
/// <summary>
/// Helper class to easier work with the registry
/// </summary>
internal static class RegistryHelper
{
/// <summary>
/// A list that contain all registry base keys in a long/full version and in a short version (e.g HKLM = HKEY_LOCAL_MACHINE)
/// </summary>
private static readonly IReadOnlyDictionary<string, RegistryKey> _baseKeys = new Dictionary<string, RegistryKey>(12)
{
{ KeyName.ClassRootShort, Win32.Registry.ClassesRoot },
{ Win32.Registry.ClassesRoot.Name, Win32.Registry.ClassesRoot },
{ KeyName.CurrentConfigShort, Win32.Registry.CurrentConfig },
{ Win32.Registry.CurrentConfig.Name, Win32.Registry.CurrentConfig },
{ KeyName.CurrentUserShort, Win32.Registry.CurrentUser },
{ Win32.Registry.CurrentUser.Name, Win32.Registry.CurrentUser },
{ KeyName.LocalMachineShort, Win32.Registry.LocalMachine },
{ Win32.Registry.LocalMachine.Name, Win32.Registry.LocalMachine },
{ KeyName.PerformanceDataShort, Win32.Registry.PerformanceData },
{ Win32.Registry.PerformanceData.Name, Win32.Registry.PerformanceData },
{ KeyName.UsersShort, Win32.Registry.Users },
{ Win32.Registry.Users.Name, Win32.Registry.Users },
};
/// <summary>
/// Try to find registry base keys based on the given query
/// </summary>
/// <param name="query">The query to search</param>
/// <returns>A combination of a list of base <see cref="RegistryKey"/> and the sub keys</returns>
internal static (IEnumerable<RegistryKey>? BaseKey, string SubKey) GetRegistryBaseKey(in string query)
{
if (string.IsNullOrWhiteSpace(query))
{
return (null, string.Empty);
}
var baseKey = query.Split('\\').FirstOrDefault() ?? string.Empty;
var subKey = query.Replace(baseKey, string.Empty, StringComparison.InvariantCultureIgnoreCase).TrimStart('\\');
var baseKeyResult = _baseKeys
.Where(found => found.Key.StartsWith(baseKey, StringComparison.InvariantCultureIgnoreCase))
.Select(found => found.Value)
.Distinct();
return (baseKeyResult, subKey);
}
/// <summary>
/// Return a list of all registry base key
/// </summary>
/// <returns>A list with all registry base keys</returns>
internal static ICollection<RegistryEntry> GetAllBaseKeys()
{
return new Collection<RegistryEntry>
{
new RegistryEntry(Win32.Registry.ClassesRoot),
new RegistryEntry(Win32.Registry.CurrentConfig),
new RegistryEntry(Win32.Registry.CurrentUser),
new RegistryEntry(Win32.Registry.LocalMachine),
new RegistryEntry(Win32.Registry.PerformanceData),
new RegistryEntry(Win32.Registry.Users),
};
}
/// <summary>
/// Search for the given sub-key path in the given registry base key
/// </summary>
/// <param name="baseKey">The base <see cref="RegistryKey"/></param>
/// <param name="subKeyPath">The path of the registry sub-key</param>
/// <returns>A list with all found registry keys</returns>
internal static ICollection<RegistryEntry> SearchForSubKey(in RegistryKey baseKey, in string subKeyPath)
{
if (string.IsNullOrEmpty(subKeyPath))
{
return FindSubKey(baseKey, string.Empty);
}
var subKeysNames = subKeyPath.Split('\\');
var index = 0;
RegistryKey? subKey = baseKey;
ICollection<RegistryEntry> result;
do
{
result = FindSubKey(subKey, subKeysNames.ElementAtOrDefault(index) ?? string.Empty);
if (result.Count == 0)
{
// If a subKey can't be found, show no results.
break;
}
if (result.Count == 1 && index < subKeysNames.Length)
{
subKey = result.First().Key;
}
if (result.Count > 1 || subKey == null)
{
break;
}
index++;
}
while (index < subKeysNames.Length);
return result;
}
/// <summary>
/// Return a human readable summary of a given <see cref="RegistryKey"/>
/// </summary>
/// <param name="key">The <see cref="RegistryKey"/> for the summary</param>
/// <returns>A human readable summary</returns>
internal static string GetSummary(in RegistryKey key)
{
return $"{Resources.SubKeys} {key.SubKeyCount} - {Resources.Values} {key.ValueCount}";
}
/// <summary>
/// Open a given registry key in the registry editor
/// </summary>
/// <param name="fullKey">The registry key to open</param>
internal static void OpenRegistryKey(in string fullKey)
{
// it's impossible to directly open a key via command-line option, so we must override the last remember key
Win32.Registry.SetValue(@"HKEY_Current_User\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit", "LastKey", fullKey);
// -m => allow multi-instance (hidden start option)
Wox.Infrastructure.Helper.OpenInShell("regedit.exe", "-m", null, Wox.Infrastructure.Helper.ShellRunAsType.Administrator);
}
/// <summary>
/// Try to find the given registry sub-key in the given registry parent-key
/// </summary>
/// <param name="parentKey">The parent-key, also the root to start the search</param>
/// <param name="searchSubKey">The sub-key to find</param>
/// <returns>A list with all found registry sub-keys</returns>
private static ICollection<RegistryEntry> FindSubKey(in RegistryKey parentKey, in string searchSubKey)
{
var list = new Collection<RegistryEntry>();
try
{
foreach (var subKey in parentKey.GetSubKeyNames().OrderBy(found => found))
{
if (!subKey.StartsWith(searchSubKey, StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
if (string.Equals(subKey, searchSubKey, StringComparison.OrdinalIgnoreCase))
{
var key = parentKey.OpenSubKey(subKey, RegistryKeyPermissionCheck.ReadSubTree);
if (key != null)
{
list.Add(new RegistryEntry(key));
}
return list;
}
try
{
var key = parentKey.OpenSubKey(subKey, RegistryKeyPermissionCheck.ReadSubTree);
if (key != null)
{
list.Add(new RegistryEntry(key));
}
}
catch (Exception exception)
{
list.Add(new RegistryEntry($"{parentKey.Name}\\{subKey}", exception));
}
}
}
catch (Exception ex)
{
list.Add(new RegistryEntry(parentKey.Name, ex));
}
return list;
}
/// <summary>
/// Return a list with a registry sub-keys of the given registry parent-key
/// </summary>
/// <param name="parentKey">The registry parent-key</param>
/// <param name="maxCount">(optional) The maximum count of the results</param>
/// <returns>A list with all found registry sub-keys</returns>
private static ICollection<RegistryEntry> GetAllSubKeys(in RegistryKey parentKey, in int maxCount = 50)
{
var list = new Collection<RegistryEntry>();
try
{
foreach (var subKey in parentKey.GetSubKeyNames())
{
if (list.Count >= maxCount)
{
break;
}
list.Add(new RegistryEntry(parentKey));
}
}
catch (Exception exception)
{
list.Add(new RegistryEntry(parentKey.Name, exception));
}
return list;
}
}
}