[PT Run] Registry plugin (#7951)
This commit is contained in:
parent
da33d22c85
commit
a434d6047f
12
.github/actions/spell-check/expect.txt
vendored
12
.github/actions/spell-check/expect.txt
vendored
|
@ -848,11 +848,15 @@ hinstance
|
|||
hitinfo
|
||||
HIWORD
|
||||
hk
|
||||
HKCR
|
||||
HKCC
|
||||
HKCU
|
||||
HKCR
|
||||
HKE
|
||||
hkey
|
||||
HKL
|
||||
HKLM
|
||||
HKPD
|
||||
HKU
|
||||
HLOCAL
|
||||
HLSL
|
||||
hmenu
|
||||
|
@ -1161,6 +1165,7 @@ Kybd
|
|||
LAlt
|
||||
lambson
|
||||
lamotile
|
||||
langword
|
||||
Lastdevice
|
||||
LASTEXITCODE
|
||||
laute
|
||||
|
@ -1197,6 +1202,7 @@ linkid
|
|||
Linkmenu
|
||||
linq
|
||||
LINQTo
|
||||
Linux
|
||||
listbox
|
||||
listview
|
||||
llkhf
|
||||
|
@ -1765,6 +1771,7 @@ REFCLSID
|
|||
refcount
|
||||
REFIID
|
||||
REGCLS
|
||||
regedit
|
||||
regex
|
||||
REGISTERCLASSFAILED
|
||||
registrypath
|
||||
|
@ -2092,6 +2099,7 @@ SYSCOLORCHANGE
|
|||
SYSCOMMAND
|
||||
SYSDEADCHAR
|
||||
SYSICONINDEX
|
||||
sysinfo
|
||||
SYSKEY
|
||||
syskeydown
|
||||
syskeyup
|
||||
|
@ -2516,4 +2524,4 @@ zoneset
|
|||
ZONESETCHANGE
|
||||
Zoneszonabletester
|
||||
Zoomusingmagnifier
|
||||
zzz
|
||||
zzz
|
13
.github/actions/spell-check/patterns.txt
vendored
13
.github/actions/spell-check/patterns.txt
vendored
|
@ -32,3 +32,16 @@ TestCase\("[^"]+"
|
|||
\\testapp
|
||||
\\tests
|
||||
\\tools
|
||||
|
||||
# plugin.json
|
||||
^ "ID": "[0-9A-F]{32}",$
|
||||
|
||||
# UnitTests
|
||||
\[DataRow\(.*\)\]
|
||||
|
||||
# Id info inside markdown file (registry.md)
|
||||
^\|\s+ID\s+\|\s*\`[0-9A-F]{32}\`
|
||||
|
||||
# marker for ignoring a comment to the end of the line
|
||||
^.*/\* #no-spell-check-line \*/.*$
|
||||
// #no-spell-check.*$
|
|
@ -118,6 +118,8 @@ build:
|
|||
- 'modules\launcher\Plugins\Microsoft.Plugin.Program\Wox.Infrastructure.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Program\Wox.Plugin.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Program\Telemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Microsoft.PowerToys.Run.Plugin.Registry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Shell\Microsoft.Plugin.Shell.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Shell\Wox.Infrastructure.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Shell\Wox.Plugin.dll'
|
||||
|
|
|
@ -305,6 +305,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Telemetry", "Telemetry", "{
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Common.UI", "src\common\Microsoft.PowerToys.Common.UI\Microsoft.PowerToys.Common.UI.csproj", "{C3A17DCA-217B-462C-BB0C-BE086AF80081}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.Registry", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Microsoft.PowerToys.Run.Plugin.Registry.csproj", "{4BABF3FE-3451-42FD-873F-3C332E18DCEF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.Registry.UnitTests", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry.UnitTest\Microsoft.PowerToys.Run.Plugin.Registry.UnitTests.csproj", "{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -619,6 +623,14 @@ Global
|
|||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.Build.0 = Debug|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.ActiveCfg = Release|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.Build.0 = Release|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.Build.0 = Debug|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.ActiveCfg = Release|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.Build.0 = Release|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.Build.0 = Debug|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.ActiveCfg = Release|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -711,6 +723,8 @@ Global
|
|||
{B39DC643-4663-475E-B329-03F0C9918D48} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{8F62026A-294B-41C6-8839-87463613F216} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
|
101
doc/devdocs/modules/launcher/plugins/registry.md
Normal file
101
doc/devdocs/modules/launcher/plugins/registry.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
# Registry Plugin
|
||||
|
||||
The registry plugin allows users to search the Windows registry.
|
||||
|
||||
## Special functions (differ from the regular functions)
|
||||
|
||||
* Support full base keys and short base keys (e.g. `HKLM` for `HKEY_LOCALE_MACHINE`).
|
||||
* Show count of subkeys and count of values in the second result line.
|
||||
* Search for value names and value data inside a registry key (syntax: `[RegistryKey]\\[ValueName]` and `[RegistryKey]\\[ValueData]`)
|
||||
|
||||
## The Windows Registry
|
||||
|
||||
The registry contains all settings for the Windows operating system and many settings of the installed (Windows only) programs.
|
||||
|
||||
*Note: Linux and macOS program ports typical store the settings in it's own configuration files and not in the Windows registry.*
|
||||
|
||||
For more information about the Windows registry, see [the official documentation](https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry).
|
||||
|
||||
For advanced information about the Windows registry, see [Windows registry information for advanced users](https://docs.microsoft.com/en-us/troubleshoot/windows-server/performance/windows-registry-advanced-users).
|
||||
|
||||
## Score
|
||||
|
||||
The score is currently not set on the results.
|
||||
|
||||
## Important for developers
|
||||
|
||||
### General
|
||||
|
||||
* The assembly name is cached into `_assemblyName` (to avoid to many calls of `Assembly.GetExecutingAssembly()`)
|
||||
|
||||
### Results
|
||||
|
||||
* All results override the visible search result via `QueryTextDisplay` to avoid problems with short registry base keys (e.g. `HKLM`).
|
||||
* The length of a `Title` and `Subtitle` is automatic truncated, when it is to long.
|
||||
|
||||
## Microsoft.Plugin.Registry project
|
||||
|
||||
### Important plugin values (meta-data)
|
||||
|
||||
| Name | Value |
|
||||
| --------------- | --------------------------------------------- |
|
||||
| ActionKeyword | `:` |
|
||||
| ExecuteFileName | `Microsoft.PowerToys.Run.Plugin.Registry.dll` |
|
||||
| ID | `303417D927BF4C97BCFFC78A123BE0C8` |
|
||||
|
||||
### Interfaces used by this plugin
|
||||
|
||||
The plugin use only these interfaces (all inside the `Main.cs`):
|
||||
|
||||
* `Wox.Plugin.IPlugin`
|
||||
* `Wox.Plugin.IContextMenu`
|
||||
* `Wox.Plugin.IPluginI18n`
|
||||
* `System.IDisposable`
|
||||
|
||||
### Program files
|
||||
|
||||
| File | Content |
|
||||
| ------------------------------------ | ------------------------------------------------------------------------ |
|
||||
| `Classes\RegistryEntry.cs` | Wrapper class for a registry key with a possible exception on access |
|
||||
| `Constants\KeyName.cs` | Static used short registry key names (to avoid code and string doubling) |
|
||||
| `Constants\MaxTextLength.cs` | Contain all maximum text lengths (for truncating) |
|
||||
| `Enumeration\TruncateSide.cs` | Contain the possible truncate sides |
|
||||
| `Helper\ContextMenuHelper.cs` | All functions to build the context menu (for each result entry) |
|
||||
| `Helper\QueryHelper.cs` | All functions to analyze the search query |
|
||||
| `Helper\RegistryHelper.cs` | All functions to search into the Windows registry (via `Win32.Registry`) |
|
||||
| `Helper\ResultHelper.cs` | All functions to convert internal results into WOX results |
|
||||
| `Helper\ValueHelper.cs` | All functions to convert values into human readable values |
|
||||
| `Images\reg.dark.png` | Symbol for the results for the dark theme |
|
||||
| `Images\reg.light.png` | Symbol for the results for the light theme |
|
||||
| `Properties\Resources.Designer.resx` | File that contain all translatable keys |
|
||||
| `Properties\Resources.resx` | File that contain all translatable strings in the neutral language |
|
||||
| `GlobalSuppressions.cs` | Code suppressions (no real file, linked via *.csproj) |
|
||||
| `Main.cs` | Main class, the only place that implement the WOX interfaces |
|
||||
| `plugin.json` | All meta-data for this plugin |
|
||||
| `StyleCop.json` | Code style (no real file, linked via *.csproj) |
|
||||
|
||||
### Important project values (*.csproj)
|
||||
|
||||
| Name | Value |
|
||||
| --------------- | ------------------------------------------------------------------------------ |
|
||||
| TargetFramework | `netcoreapp3.1` (means .NET Core 3.1) |
|
||||
| LangVersion | `8.0` (mean C# 8.0) |
|
||||
| Platforms | `x64` |
|
||||
| Nullable | `true` |
|
||||
| Output | `..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Registry\` |
|
||||
| RootNamespace | `Microsoft.PowerToys.Run.Plugin.Registry` |
|
||||
| AssemblyName | `Microsoft.PowerToys.Run.Plugin.Registry` |
|
||||
|
||||
### Project dependencies
|
||||
|
||||
#### Packages
|
||||
|
||||
| Package | Version |
|
||||
| ------------------------------------------------------------------------------------- | ------- |
|
||||
| [`Microsoft.CodeAnalysis.FxCopAnalyzers`](https://github.com/dotnet/roslyn-analyzers) | 3.3.0 |
|
||||
| [`StyleCop.Analyzers`](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) | 1.1.118 |
|
||||
|
||||
#### Projects
|
||||
|
||||
* `Wox.Infrastructure`
|
||||
* `Wox.Plugin`
|
|
@ -9,7 +9,8 @@
|
|||
- [Folder](/doc/devdocs/modules/launcher/plugins/folder.md)
|
||||
- [Indexer](/doc/devdocs/modules/launcher/plugins/indexer.md)
|
||||
- [Program](/doc/devdocs/modules/launcher/plugins/program.md)
|
||||
- [Registry](/doc/devdocs/modules/launcher/plugins/registry.md)
|
||||
- [Shell](/doc/devdocs/modules/launcher/plugins/shell.md)
|
||||
- [Sys](/doc/devdocs/modules/launcher/plugins/sys.md)
|
||||
- [Uri](/doc/devdocs/modules/launcher/plugins/uri.md)
|
||||
- [Window Walker](/doc/devdocs/modules/launcher/plugins/windowwalker.md)
|
||||
- [Window Walker](/doc/devdocs/modules/launcher/plugins/windowwalker.md)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// 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 Microsoft.PowerToys.Run.Plugin.Registry.Constants;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.UnitTest.Constants
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class KeyNameTest
|
||||
{
|
||||
[TestMethod]
|
||||
[DataRow("HKEY", KeyName.FirstPart)]
|
||||
[DataRow("HKEY_", KeyName.FirstPartUnderscore)]
|
||||
[DataRow("HKCR", KeyName.ClassRootShort)]
|
||||
[DataRow("HKCC", KeyName.CurrentConfigShort)]
|
||||
[DataRow("HKCU", KeyName.CurrentUserShort)]
|
||||
[DataRow("HKLM", KeyName.LocalMachineShort)]
|
||||
[DataRow("HKPD", KeyName.PerformanceDataShort)]
|
||||
[DataRow("HKU", KeyName.UsersShort)]
|
||||
public void TestConstants(string shortName, string baseName)
|
||||
{
|
||||
Assert.AreEqual(shortName, baseName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// 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 Microsoft.PowerToys.Run.Plugin.Registry.Helper;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.UnitTest.Helper
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class QueryHelperTest
|
||||
{
|
||||
[TestMethod]
|
||||
[DataRow(@"HKLM", false, @"HKLM", "")]
|
||||
[DataRow(@"HKLM\", false, @"HKLM\", "")]
|
||||
[DataRow(@"HKLM\\", true, @"HKLM", "")]
|
||||
[DataRow(@"HKLM\\Test", true, @"HKLM", "Test")]
|
||||
[DataRow(@"HKLM\Test\\TestTest", true, @"HKLM\Test", "TestTest")]
|
||||
[DataRow(@"HKLM\Test\\\TestTest", true, @"HKLM\Test", @"\TestTest")]
|
||||
public void GetQueryPartsTest(string query, bool expectedHasValueName, string expectedQueryKey, string expectedQueryValueName)
|
||||
{
|
||||
var hasValueName = QueryHelper.GetQueryParts(query, out var queryKey, out var queryValueName);
|
||||
|
||||
Assert.AreEqual(expectedHasValueName, hasValueName);
|
||||
Assert.AreEqual(expectedQueryKey, queryKey);
|
||||
Assert.AreEqual(expectedQueryValueName, queryValueName);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DataRow(@"HKCR\*\OpenWithList", @"HKEY_CLASSES_ROOT\*\OpenWithList")]
|
||||
[DataRow(@"HKCU\Control Panel\Accessibility", @"HKEY_CURRENT_USER\Control Panel\Accessibility")]
|
||||
[DataRow(@"HKLM\HARDWARE\UEFI", @"HKEY_LOCAL_MACHINE\HARDWARE\UEFI")]
|
||||
[DataRow(@"HKU\.DEFAULT\Environment", @"HKEY_USERS\.DEFAULT\Environment")]
|
||||
[DataRow(@"HKCC\System\CurrentControlSet\Control", @"HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control")]
|
||||
[DataRow(@"HKPD\???", @"HKEY_PERFORMANCE_DATA\???")]
|
||||
public void GetShortBaseKeyTest(string registryKeyShort, string registryKeyFull)
|
||||
{
|
||||
Assert.AreEqual(registryKeyShort, QueryHelper.GetKeyWithShortBaseKey(registryKeyFull));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// 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.Collections;
|
||||
using System.Linq;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Helper;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.UnitTest.Helper
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class RegistryHelperTest
|
||||
{
|
||||
[TestMethod]
|
||||
[DataRow(@"HKCC\System\CurrentControlSet\Control", "HKEY_CURRENT_CONFIG")]
|
||||
[DataRow(@"HKCR\*\OpenWithList", "HKEY_CLASSES_ROOT")]
|
||||
[DataRow(@"HKCU\Control Panel\Accessibility", "HKEY_CURRENT_USER")]
|
||||
[DataRow(@"HKLM\HARDWARE\UEFI", "HKEY_LOCAL_MACHINE")]
|
||||
[DataRow(@"HKPD\???", "HKEY_PERFORMANCE_DATA")]
|
||||
[DataRow(@"HKU\.DEFAULT\Environment", "HKEY_USERS")]
|
||||
public void GetRegistryBaseKeyTestOnlyOneBaseKey(string query, string expectedBaseKey)
|
||||
{
|
||||
var (baseKeyList, _) = RegistryHelper.GetRegistryBaseKey(query);
|
||||
Assert.IsTrue(baseKeyList.Count() == 1);
|
||||
Assert.AreEqual(expectedBaseKey, baseKeyList.FirstOrDefault().Name);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetRegistryBaseKeyTestMoreThanOneBaseKey()
|
||||
{
|
||||
var (baseKeyList, _) = RegistryHelper.GetRegistryBaseKey("HKC\\Control Panel\\Accessibility"); /* #no-spell-check-line */
|
||||
|
||||
Assert.IsTrue(baseKeyList.Count() > 1);
|
||||
|
||||
var list = baseKeyList.Select(found => found.Name);
|
||||
Assert.IsTrue(list.Contains("HKEY_CLASSES_ROOT"));
|
||||
Assert.IsTrue(list.Contains("HKEY_CURRENT_CONFIG"));
|
||||
Assert.IsTrue(list.Contains("HKEY_CURRENT_USER"));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DataRow(@"HKCR\*\OpenWithList", @"*\OpenWithList")]
|
||||
[DataRow(@"HKCU\Control Panel\Accessibility", @"Control Panel\Accessibility")]
|
||||
[DataRow(@"HKLM\HARDWARE\UEFI", @"HARDWARE\UEFI")]
|
||||
[DataRow(@"HKU\.DEFAULT\Environment", @".DEFAULT\Environment")]
|
||||
[DataRow(@"HKCC\System\CurrentControlSet\Control", @"System\CurrentControlSet\Control")]
|
||||
[DataRow(@"HKPD\???", @"???")]
|
||||
public void GetRegistryBaseKeyTestSubKey(string query, string expectedSubKey)
|
||||
{
|
||||
var (_, subKey) = RegistryHelper.GetRegistryBaseKey(query);
|
||||
Assert.AreEqual(expectedSubKey, subKey);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetAllBaseKeysTest()
|
||||
{
|
||||
var list = RegistryHelper.GetAllBaseKeys();
|
||||
|
||||
CollectionAssert.AllItemsAreNotNull((ICollection)list);
|
||||
CollectionAssert.AllItemsAreUnique((ICollection)list);
|
||||
|
||||
var keys = list.Select(found => found.Key).ToList() as ICollection;
|
||||
|
||||
CollectionAssert.Contains(keys, Win32.Registry.ClassesRoot);
|
||||
CollectionAssert.Contains(keys, Win32.Registry.CurrentConfig);
|
||||
CollectionAssert.Contains(keys, Win32.Registry.CurrentUser);
|
||||
CollectionAssert.Contains(keys, Win32.Registry.LocalMachine);
|
||||
CollectionAssert.Contains(keys, Win32.Registry.PerformanceData);
|
||||
CollectionAssert.Contains(keys, Win32.Registry.Users);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// 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 Microsoft.PowerToys.Run.Plugin.Registry.Helper;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.UnitTest.Helper
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class ResultHelperTest
|
||||
{
|
||||
[TestMethod]
|
||||
[DataRow(@"HKEY_CLASSES_ROOT\*\OpenWithList", @"HKEY_CLASSES_ROOT\*\OpenWithList")]
|
||||
[DataRow(@"HKEY_CURRENT_USER\Control Panel\Accessibility", @"HKEY_CURRENT_USER\Control Panel\Accessibility")]
|
||||
[DataRow(@"HKEY_LOCAL_MACHINE\HARDWARE\UEFI", @"HKEY_LOCAL_MACHINE\HARDWARE\UEFI")]
|
||||
[DataRow(@"HKEY_USERS\.DEFAULT\Environment", @"HKEY_USERS\.DEFAULT\Environment")]
|
||||
[DataRow(@"HKCC\System\CurrentControlSet\Control", @"HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control")]
|
||||
[DataRow(@"HKEY_PERFORMANCE_DATA\???", @"HKEY_PERFORMANCE_DATA\???")]
|
||||
[DataRow(@"HKCR\*\shell\Open with VS Code\command", @"HKEY_CLASSES_ROOT\*\shell\Open with VS Code\command")]
|
||||
[DataRow(@"...ndows\CurrentVersion\Explorer\StartupApproved", @"HKEY_CURRENT_USER\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved")]
|
||||
[DataRow(@"...p\Upgrade\NetworkDriverBackup\Control\Network", @"HKEY_LOCAL_MACHINE\SYSTEM\Setup\Upgrade\NetworkDriverBackup\Control\Network")]
|
||||
[DataRow(@"...anel\International\User Profile System Backup", @"HKEY_USERS\.DEFAULT\Control Panel\International\User Profile System Backup")]
|
||||
[DataRow(@"...stem\CurrentControlSet\Control\Print\Printers", @"HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control\Print\Printers")]
|
||||
public void GetTruncatedTextTest(string registryKeyShort, string registryKeyFull)
|
||||
{
|
||||
Assert.AreEqual(registryKeyShort, ResultHelper.GetTruncatedText(registryKeyFull, 45));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Optimize>false</Optimize>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\..\codeAnalysis\GlobalSuppressions.cs">
|
||||
<Link>GlobalSuppressions.cs</Link>
|
||||
</Compile>
|
||||
<AdditionalFiles Include="..\..\..\..\codeAnalysis\StyleCop.json">
|
||||
<Link>StyleCop.json</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.PowerToys.Run.Plugin.Registry\Microsoft.PowerToys.Run.Plugin.Registry.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,113 @@
|
|||
// 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 Microsoft.PowerToys.Run.Plugin.Registry.Helper;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.Classes
|
||||
{
|
||||
/// <summary>
|
||||
/// A entry of the registry.
|
||||
/// </summary>
|
||||
internal class RegistryEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the full path to a registry key.
|
||||
/// </summary>
|
||||
internal string KeyPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registry key for this entry.
|
||||
/// </summary>
|
||||
internal RegistryKey? Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a possible exception that was occurred when try to open this registry key (e.g. <see cref="UnauthorizedAccessException"/>).
|
||||
/// </summary>
|
||||
internal Exception? Exception { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the current selected registry value.
|
||||
/// </summary>
|
||||
internal string? ValueName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the current selected registry value.
|
||||
/// </summary>
|
||||
internal object? ValueData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegistryEntry"/> class.
|
||||
/// </summary>
|
||||
/// <param name="keyPath">The full path to the registry key for this entry.</param>
|
||||
/// <param name="exception">A exception that was occurred when try to access this registry key.</param>
|
||||
internal RegistryEntry(string keyPath, Exception exception)
|
||||
{
|
||||
KeyPath = keyPath;
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegistryEntry"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The <see cref="RegistryKey"/> for this entry.</param>
|
||||
internal RegistryEntry(RegistryKey key)
|
||||
{
|
||||
KeyPath = key.Name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegistryEntry"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The <see cref="RegistryKey"/> for this entry.</param>
|
||||
/// <param name="valueName">The value name of the current selected registry value.</param>
|
||||
/// <param name="value">The value of the current selected registry value.</param>
|
||||
internal RegistryEntry(RegistryKey key, string valueName, object value)
|
||||
{
|
||||
KeyPath = key.Name;
|
||||
Key = key;
|
||||
ValueName = valueName;
|
||||
ValueData = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the registry key.
|
||||
/// </summary>
|
||||
/// <returns>A registry key.</returns>
|
||||
internal string GetRegistryKey()
|
||||
{
|
||||
return $"{Key?.Name ?? KeyPath}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the value name with the complete registry key.
|
||||
/// </summary>
|
||||
/// <returns>A value name with the complete registry key.</returns>
|
||||
internal string GetValueNameWithKey()
|
||||
{
|
||||
return $"{Key?.Name ?? KeyPath}\\\\{ValueName?.ToString() ?? string.Empty}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the value data of a value name inside a registry key.
|
||||
/// </summary>
|
||||
/// <returns>A value data.</returns>
|
||||
internal string GetValueData()
|
||||
{
|
||||
if (Key is null)
|
||||
{
|
||||
return KeyPath;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ValueName))
|
||||
{
|
||||
return Key.Name;
|
||||
}
|
||||
|
||||
return ValueHelper.GetValue(Key, ValueName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// 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.PowerToys.Run.Plugin.Registry.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// This class contains names for important registry keys
|
||||
/// </summary>
|
||||
internal static class KeyName
|
||||
{
|
||||
/// <summary>
|
||||
/// The first name part of each base key without the underscore
|
||||
/// </summary>
|
||||
internal const string FirstPart = "HKEY";
|
||||
|
||||
/// <summary>
|
||||
/// The first name part of each base key follow by a underscore
|
||||
/// </summary>
|
||||
internal const string FirstPartUnderscore = "HKEY_";
|
||||
|
||||
/// <summary>
|
||||
/// The short name for the base key HKEY_CLASSES_ROOT (see <see cref="Win32.Registry.ClassesRoot"/>)
|
||||
/// </summary>
|
||||
internal const string ClassRootShort = "HKCR";
|
||||
|
||||
/// <summary>
|
||||
/// The short name for the base key HKEY_CURRENT_CONFIG (see <see cref="Win32.Registry.CurrentConfig"/>)
|
||||
/// </summary>
|
||||
internal const string CurrentConfigShort = "HKCC";
|
||||
|
||||
/// <summary>
|
||||
/// The short name for the base key HKEY_CURRENT_USER (see <see cref="Win32.Registry.CurrentUser"/>)
|
||||
/// </summary>
|
||||
internal const string CurrentUserShort = "HKCU";
|
||||
|
||||
/// <summary>
|
||||
/// The short name for the base key HKEY_LOCAL_MACHINE (see <see cref="Win32.Registry.LocalMachine"/>)
|
||||
/// </summary>
|
||||
internal const string LocalMachineShort = "HKLM";
|
||||
|
||||
/// <summary>
|
||||
/// The short name for the base key HKEY_PERFORMANCE_DATA (see <see cref="Win32.Registry.PerformanceData"/>)
|
||||
/// </summary>
|
||||
internal const string PerformanceDataShort = "HKPD";
|
||||
|
||||
/// <summary>
|
||||
/// The short name for the base key HKEY_USERS (see <see cref="Win32.Registry.Users"/>)
|
||||
/// </summary>
|
||||
internal const string UsersShort = "HKU";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// 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.PowerToys.Run.Plugin.Registry.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// This class contain all maximum text length.
|
||||
/// </summary>
|
||||
public static class MaxTextLength
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum length for the title text length with two context menu symbols on the right.
|
||||
/// </summary>
|
||||
internal const int MaximumTitleLengthWithTwoSymbols = 44;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum length for the title text length with three context menu symbols on the right.
|
||||
/// </summary>
|
||||
internal const int MaximumTitleLengthWithThreeSymbols = 40;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum length for the sub-title text length with two context menu symbols on the right.
|
||||
/// </summary>
|
||||
internal const int MaximumSubTitleLengthWithTwoSymbols = 85;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum length for the sub-title text length with three context menu symbols on the right.
|
||||
/// </summary>
|
||||
internal const int MaximumSubTitleLengthWithThreeSymbols = 78;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// 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.PowerToys.Run.Plugin.Registry.Enumerations
|
||||
{
|
||||
/// <summary>
|
||||
/// The truncate side for a to long text
|
||||
/// </summary>
|
||||
internal enum TruncateSide
|
||||
{
|
||||
/// <summary>
|
||||
/// Truncate a text only from the right side
|
||||
/// </summary>
|
||||
OnlyFromLeft,
|
||||
|
||||
/// <summary>
|
||||
/// Truncate a text only from the left side
|
||||
/// </summary>
|
||||
OnlyFromRight,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
// 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.Windows;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Classes;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Properties;
|
||||
using Wox.Plugin;
|
||||
using Wox.Plugin.Logger;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to easier work with context menu entries
|
||||
/// </summary>
|
||||
internal static class ContextMenuHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Return a list with all context menu entries for the given <see cref="Result"/>
|
||||
/// <para>Symbols taken from <see href="https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font"/></para>
|
||||
/// </summary>
|
||||
/// <param name="result">The result for the context menu entires</param>
|
||||
/// <param name="assemblyName">The name of the this assembly</param>
|
||||
/// <returns>A list with context menu entries</returns>
|
||||
internal static List<ContextMenuResult> GetContextMenu(Result result, string assemblyName)
|
||||
{
|
||||
if (!(result?.ContextData is RegistryEntry entry))
|
||||
{
|
||||
return new List<ContextMenuResult>(0);
|
||||
}
|
||||
|
||||
var list = new List<ContextMenuResult>();
|
||||
|
||||
if (string.IsNullOrEmpty(entry.ValueName))
|
||||
{
|
||||
list.Add(new ContextMenuResult
|
||||
{
|
||||
AcceleratorKey = Key.C,
|
||||
AcceleratorModifiers = ModifierKeys.Control,
|
||||
Action = _ => TryToCopyToClipBoard(entry.GetRegistryKey()),
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
Glyph = "\xE8C8", // E8C8 => Symbol: Copy
|
||||
PluginName = assemblyName,
|
||||
Title = $"{Resources.CopyKeyNamePath} (Ctrl+C)",
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(new ContextMenuResult
|
||||
{
|
||||
AcceleratorKey = Key.C,
|
||||
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
|
||||
Action = _ => TryToCopyToClipBoard(entry.GetValueData()),
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
Glyph = "\xF413", // F413 => Symbol: CopyTo
|
||||
PluginName = assemblyName,
|
||||
Title = $"{Resources.CopyValueData} (Ctrl+Shift+C)",
|
||||
});
|
||||
|
||||
list.Add(new ContextMenuResult
|
||||
{
|
||||
AcceleratorKey = Key.C,
|
||||
AcceleratorModifiers = ModifierKeys.Control,
|
||||
Action = _ => TryToCopyToClipBoard(entry.GetValueNameWithKey()),
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
Glyph = "\xE8C8", // E8C8 => Symbol: Copy
|
||||
PluginName = assemblyName,
|
||||
Title = $"{Resources.CopyValueName} (Ctrl+C)",
|
||||
});
|
||||
}
|
||||
|
||||
list.Add(new ContextMenuResult
|
||||
{
|
||||
AcceleratorKey = Key.Enter,
|
||||
Action = _ => TryToOpenInRegistryEditor(entry),
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
Glyph = "\xE8A7", // E8A7 => Symbol: OpenInNewWindow
|
||||
PluginName = assemblyName,
|
||||
Title = $"{Resources.OpenKeyInRegistryEditor} (Enter)",
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
|
||||
/// <summary>
|
||||
/// Open the Windows registry editor and jump to registry key inside the given key (inside the <see cref="RegistryEntry"/>
|
||||
/// </summary>
|
||||
/// <param name="entry">The <see cref="RegistryEntry"/> to jump in</param>
|
||||
/// <returns><see langword="true"/> if the registry editor was successful open, otherwise <see langword="false"/></returns>
|
||||
internal static bool TryToOpenInRegistryEditor(in RegistryEntry entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
RegistryHelper.OpenRegistryKey(entry.Key?.Name ?? entry.KeyPath);
|
||||
return true;
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception)
|
||||
{
|
||||
MessageBox.Show(
|
||||
Resources.OpenInRegistryEditorAccessExceptionText,
|
||||
Resources.OpenInRegistryEditorAccessExceptionTitle,
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
return false;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Exception("Error on opening Windows registry editor", exception, typeof(Main));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the given text to the clipboard
|
||||
/// </summary>
|
||||
/// <param name="text">The text to copy to the clipboard</param>
|
||||
/// <returns><see langword="true"/>The text successful copy to the clipboard, otherwise <see langword="false"/></returns>
|
||||
private static bool TryToCopyToClipBoard(in string text)
|
||||
{
|
||||
try
|
||||
{
|
||||
Clipboard.Clear();
|
||||
Clipboard.SetText(text);
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Exception("Can't copy to clipboard", exception, typeof(Main));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
// 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.Linq;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Constants;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to easier work with queries
|
||||
/// </summary>
|
||||
internal static class QueryHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// The character to distinguish if the search query contain multiple parts (typically "\\")
|
||||
/// </summary>
|
||||
internal const string QuerySplitCharacter = "\\\\";
|
||||
|
||||
/// <summary>
|
||||
/// A list that contain short names of all registry base keys
|
||||
/// </summary>
|
||||
private static readonly IReadOnlyDictionary<string, string> _shortBaseKeys = new Dictionary<string, string>(6)
|
||||
{
|
||||
{ Win32.Registry.ClassesRoot.Name, KeyName.ClassRootShort },
|
||||
{ Win32.Registry.CurrentConfig.Name, KeyName.CurrentConfigShort },
|
||||
{ Win32.Registry.CurrentUser.Name, KeyName.CurrentUserShort },
|
||||
{ Win32.Registry.LocalMachine.Name, KeyName.LocalMachineShort },
|
||||
{ Win32.Registry.PerformanceData.Name, KeyName.PerformanceDataShort },
|
||||
{ Win32.Registry.Users.Name, KeyName.UsersShort },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Return the parts of a given query
|
||||
/// </summary>
|
||||
/// <param name="query">The query that could contain parts</param>
|
||||
/// <param name="queryKey">The key part of the query</param>
|
||||
/// <param name="queryValueName">The value name part of the query</param>
|
||||
/// <returns><see langword="true"/> when the query search for a key and a value name, otherwise <see langword="false"/></returns>
|
||||
internal static bool GetQueryParts(in string query, out string queryKey, out string queryValueName)
|
||||
{
|
||||
if (!query.Contains(QuerySplitCharacter, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
queryKey = query;
|
||||
queryValueName = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
var querySplit = query.Split(QuerySplitCharacter);
|
||||
|
||||
queryKey = querySplit.FirstOrDefault();
|
||||
queryValueName = querySplit.LastOrDefault();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a registry key with a long base key
|
||||
/// </summary>
|
||||
/// <param name="registryKey">A registry key with a short base key</param>
|
||||
/// <returns>A registry key with a long base key</returns>
|
||||
internal static string GetKeyWithLongBaseKey(in string registryKey)
|
||||
{
|
||||
foreach (var shortName in _shortBaseKeys)
|
||||
{
|
||||
if (!registryKey.StartsWith(shortName.Value, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return registryKey.Replace(shortName.Value, shortName.Key, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
return registryKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a registry key with a short base key (useful to reduce the text length of a registry key)
|
||||
/// </summary>
|
||||
/// <param name="registryKey">A registry key with a full base key</param>
|
||||
/// <returns>A registry key with a short base key</returns>
|
||||
internal static string GetKeyWithShortBaseKey(in string registryKey)
|
||||
{
|
||||
foreach (var shortName in _shortBaseKeys)
|
||||
{
|
||||
if (!registryKey.StartsWith(shortName.Key, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return registryKey.Replace(shortName.Key, shortName.Value, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
return registryKey;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
// 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.Diagnostics;
|
||||
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
|
||||
{
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
|
||||
/// <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();
|
||||
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;
|
||||
var subKey = baseKey;
|
||||
|
||||
ICollection<RegistryEntry> result;
|
||||
|
||||
do
|
||||
{
|
||||
result = FindSubKey(subKey, subKeysNames.ElementAtOrDefault(index));
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
return FindSubKey(subKey, string.Empty);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
var processStartInfo = new ProcessStartInfo
|
||||
{
|
||||
// -m => allow multi-instance (hidden start option)
|
||||
Arguments = "-m",
|
||||
|
||||
FileName = "regedit.exe",
|
||||
|
||||
// Start as administrator
|
||||
Verb = "runas",
|
||||
|
||||
// Start as administrator will not work without this
|
||||
UseShellExecute = true,
|
||||
};
|
||||
|
||||
Process.Start(processStartInfo);
|
||||
}
|
||||
|
||||
/// <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.InvariantCultureIgnoreCase))
|
||||
{
|
||||
list.Add(new RegistryEntry(parentKey.OpenSubKey(subKey, RegistryKeyPermissionCheck.ReadSubTree)));
|
||||
return list;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
list.Add(new RegistryEntry(parentKey.OpenSubKey(subKey, RegistryKeyPermissionCheck.ReadSubTree)));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
// 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.Linq;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Classes;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Constants;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Enumerations;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Properties;
|
||||
using Microsoft.Win32;
|
||||
using Wox.Plugin;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to easier work with results
|
||||
/// </summary>
|
||||
internal static class ResultHelper
|
||||
{
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
|
||||
/// <summary>
|
||||
/// Return a list with <see cref="Result"/>s, based on the given list
|
||||
/// </summary>
|
||||
/// <param name="list">The original result list to convert</param>
|
||||
/// <param name="iconPath">The path to the icon of each entry</param>
|
||||
/// <returns>A list with <see cref="Result"/></returns>
|
||||
internal static List<Result> GetResultList(in IEnumerable<RegistryEntry> list, in string iconPath)
|
||||
{
|
||||
var resultList = new List<Result>();
|
||||
|
||||
foreach (var entry in list)
|
||||
{
|
||||
var result = new Result
|
||||
{
|
||||
IcoPath = iconPath,
|
||||
};
|
||||
|
||||
if (entry.Exception is null && !(entry.Key is null))
|
||||
{
|
||||
// when key contains keys or fields
|
||||
result.QueryTextDisplay = entry.Key.Name;
|
||||
result.SubTitle = RegistryHelper.GetSummary(entry.Key);
|
||||
result.Title = GetTruncatedText(entry.Key.Name, MaxTextLength.MaximumTitleLengthWithTwoSymbols);
|
||||
}
|
||||
else if (entry.Key is null && !(entry.Exception is null))
|
||||
{
|
||||
// on error (e.g access denied)
|
||||
result.QueryTextDisplay = entry.KeyPath;
|
||||
result.SubTitle = GetTruncatedText(entry.Exception.Message, MaxTextLength.MaximumSubTitleLengthWithTwoSymbols, TruncateSide.OnlyFromRight);
|
||||
result.Title = GetTruncatedText(entry.KeyPath, MaxTextLength.MaximumTitleLengthWithTwoSymbols);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.QueryTextDisplay = entry.KeyPath;
|
||||
result.Title = GetTruncatedText(entry.KeyPath, MaxTextLength.MaximumTitleLengthWithTwoSymbols);
|
||||
}
|
||||
|
||||
result.Action = (_) => ContextMenuHelper.TryToOpenInRegistryEditor(entry);
|
||||
result.ContextData = entry;
|
||||
result.ToolTipData = new ToolTipData(Resources.RegistryKey, $"{Resources.KeyName}\t{result.Title}");
|
||||
|
||||
resultList.Add(result);
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list with <see cref="Result"/>s, based on the given <see cref="RegistryKey"/>
|
||||
/// </summary>
|
||||
/// <param name="key">The <see cref="RegistryKey"/> that should contain entries for the list</param>
|
||||
/// <param name="iconPath">The path to the icon of each entry</param>
|
||||
/// <param name="searchValue">(optional) When not <see cref="string.Empty"/> filter the list for the given value name and value</param>
|
||||
/// <returns>A list with <see cref="Result"/></returns>
|
||||
internal static List<Result> GetValuesFromKey(in RegistryKey? key, in string iconPath, string searchValue = "")
|
||||
{
|
||||
if (key is null)
|
||||
{
|
||||
return new List<Result>(0);
|
||||
}
|
||||
|
||||
ICollection<KeyValuePair<string, object>> valueList = new List<KeyValuePair<string, object>>(key.ValueCount);
|
||||
|
||||
var resultList = new List<Result>();
|
||||
|
||||
try
|
||||
{
|
||||
var valueNames = key.GetValueNames();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var valueName in valueNames)
|
||||
{
|
||||
valueList.Add(KeyValuePair.Create(valueName, key.GetValue(valueName)));
|
||||
}
|
||||
}
|
||||
catch (Exception valueException)
|
||||
{
|
||||
var registryEntry = new RegistryEntry(key.Name, valueException);
|
||||
|
||||
resultList.Add(new Result
|
||||
{
|
||||
ContextData = registryEntry,
|
||||
IcoPath = iconPath,
|
||||
SubTitle = GetTruncatedText(valueException.Message, MaxTextLength.MaximumSubTitleLengthWithThreeSymbols, TruncateSide.OnlyFromRight),
|
||||
Title = GetTruncatedText(key.Name, MaxTextLength.MaximumTitleLengthWithThreeSymbols),
|
||||
ToolTipData = new ToolTipData(valueException.Message, valueException.ToString()),
|
||||
Action = (_) => ContextMenuHelper.TryToOpenInRegistryEditor(registryEntry),
|
||||
QueryTextDisplay = key.Name,
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(searchValue))
|
||||
{
|
||||
var filteredValueName = valueList.Where(found => found.Key.Contains(searchValue, StringComparison.InvariantCultureIgnoreCase));
|
||||
var filteredValueList = valueList.Where(found => found.Value.ToString()?.Contains(searchValue, StringComparison.InvariantCultureIgnoreCase) ?? false);
|
||||
|
||||
valueList = filteredValueName.Concat(filteredValueList).Distinct().ToList();
|
||||
}
|
||||
|
||||
foreach (var valueEntry in valueList.OrderBy(found => found.Key))
|
||||
{
|
||||
var valueName = valueEntry.Key;
|
||||
if (string.IsNullOrEmpty(valueName))
|
||||
{
|
||||
valueName = "(Default)";
|
||||
}
|
||||
|
||||
var registryEntry = new RegistryEntry(key, valueEntry.Key, valueEntry.Value);
|
||||
|
||||
resultList.Add(new Result
|
||||
{
|
||||
ContextData = registryEntry,
|
||||
IcoPath = iconPath,
|
||||
SubTitle = GetTruncatedText(GetSubTileForRegistryValue(key, valueEntry), MaxTextLength.MaximumSubTitleLengthWithThreeSymbols, TruncateSide.OnlyFromRight),
|
||||
Title = GetTruncatedText(valueName, MaxTextLength.MaximumTitleLengthWithThreeSymbols),
|
||||
ToolTipData = new ToolTipData(Resources.RegistryValue, GetToolTipTextForRegistryValue(key, valueEntry)),
|
||||
Action = (_) => ContextMenuHelper.TryToOpenInRegistryEditor(registryEntry),
|
||||
|
||||
// Avoid user handling interrupt when move up/down inside the results of a registry key
|
||||
QueryTextDisplay = $"{key.Name}{QueryHelper.QuerySplitCharacter}",
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
var registryEntry = new RegistryEntry(key.Name, exception);
|
||||
|
||||
resultList.Add(new Result
|
||||
{
|
||||
ContextData = registryEntry,
|
||||
IcoPath = iconPath,
|
||||
SubTitle = GetTruncatedText(exception.Message, MaxTextLength.MaximumSubTitleLengthWithThreeSymbols, TruncateSide.OnlyFromRight),
|
||||
Title = GetTruncatedText(key.Name, MaxTextLength.MaximumTitleLengthWithThreeSymbols),
|
||||
ToolTipData = new ToolTipData(exception.Message, exception.ToString()),
|
||||
Action = (_) => ContextMenuHelper.TryToOpenInRegistryEditor(registryEntry),
|
||||
QueryTextDisplay = key.Name,
|
||||
});
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
|
||||
/// <summary>
|
||||
/// Return a truncated name
|
||||
/// </summary>
|
||||
/// <param name="text">The text to truncate</param>
|
||||
/// <param name="maxLength">The maximum length of the text</param>
|
||||
/// <param name="truncateSide">(optional) The side of the truncate</param>
|
||||
/// <returns>A truncated text with a maximum length</returns>
|
||||
internal static string GetTruncatedText(string text, in int maxLength, TruncateSide truncateSide = TruncateSide.OnlyFromLeft)
|
||||
{
|
||||
if (truncateSide == TruncateSide.OnlyFromLeft)
|
||||
{
|
||||
if (text.Length > maxLength)
|
||||
{
|
||||
text = QueryHelper.GetKeyWithShortBaseKey(text);
|
||||
}
|
||||
|
||||
return text.Length > maxLength ? $"...{text[^maxLength..]}" : text;
|
||||
}
|
||||
else
|
||||
{
|
||||
return text.Length > maxLength ? $"{text[0..maxLength]}..." : text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the tool-tip text for a registry value
|
||||
/// </summary>
|
||||
/// <param name="key">The registry key for the tool-tip</param>
|
||||
/// <param name="valueEntry">The value name and value of the registry value</param>
|
||||
/// <returns>A tool-tip text</returns>
|
||||
private static string GetToolTipTextForRegistryValue(RegistryKey key, KeyValuePair<string, object> valueEntry)
|
||||
{
|
||||
return $"{Resources.KeyName}\t{key.Name}{Environment.NewLine}"
|
||||
+ $"{Resources.Name}\t{valueEntry.Key}{Environment.NewLine}"
|
||||
+ $"{Resources.Type}\t{ValueHelper.GetType(key, valueEntry.Key)}{Environment.NewLine}"
|
||||
+ $"{Resources.Value}\t{ValueHelper.GetValue(key, valueEntry.Key)}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the sub-title text for a registry value
|
||||
/// </summary>
|
||||
/// <param name="key">The registry key for the sub-title</param>
|
||||
/// <param name="valueEntry">The value name and value of the registry value</param>
|
||||
/// <returns>A sub-title text</returns>
|
||||
private static string GetSubTileForRegistryValue(RegistryKey key, KeyValuePair<string, object> valueEntry)
|
||||
{
|
||||
return $"{Resources.Type} {ValueHelper.GetType(key, valueEntry.Key)}"
|
||||
+ $" - {Resources.Value} {ValueHelper.GetValue(key, valueEntry.Key, 50)}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// 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.Linq;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Properties;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to easier work with values of a <see cref="RegistryKey"/>
|
||||
/// </summary>
|
||||
internal static class ValueHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Return a human readable value data, of the given value name inside the given <see cref="RegistryKey"/>
|
||||
/// </summary>
|
||||
/// <param name="key">The <see cref="RegistryKey"/> that should contain the value name.</param>
|
||||
/// <param name="valueName">The name of the value.</param>
|
||||
/// <param name="maxLength">The maximum length for the human readable value.</param>
|
||||
/// <returns>A human readable value data.</returns>
|
||||
internal static string GetValue(in RegistryKey key, in string valueName, int maxLength = int.MaxValue)
|
||||
{
|
||||
var unformattedValue = key.GetValue(valueName);
|
||||
|
||||
var valueData = key.GetValueKind(valueName) switch
|
||||
{
|
||||
RegistryValueKind.DWord => $"0x{unformattedValue:X8} ({(uint)(int)unformattedValue})",
|
||||
RegistryValueKind.QWord => $"0x{unformattedValue:X16} ({(ulong)(long)unformattedValue})",
|
||||
RegistryValueKind.Binary => (unformattedValue as byte[]).Aggregate(string.Empty, (current, singleByte) => $"{current} {singleByte:X2}"),
|
||||
_ => $"{unformattedValue}",
|
||||
};
|
||||
|
||||
return valueData.Length > maxLength
|
||||
? $"{valueData.Substring(0, maxLength)}..."
|
||||
: valueData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the registry type name of a given value name inside a given <see cref="RegistryKey"/>
|
||||
/// </summary>
|
||||
/// <param name="key">The <see cref="RegistryKey"/> that should contain the value name</param>
|
||||
/// <param name="valueName">The name of the value</param>
|
||||
/// <returns>A registry type name</returns>
|
||||
internal static object GetType(RegistryKey key, string valueName)
|
||||
{
|
||||
return key.GetValueKind(valueName) switch
|
||||
{
|
||||
RegistryValueKind.None => Resources.RegistryValueKindNone,
|
||||
RegistryValueKind.Unknown => Resources.RegistryValueKindUnknown,
|
||||
RegistryValueKind.String => "REG_SZ",
|
||||
RegistryValueKind.ExpandString => "REG_EXPAND_SZ",
|
||||
RegistryValueKind.MultiString => "REG_MULTI_SZ",
|
||||
RegistryValueKind.Binary => "REG_BINARY",
|
||||
RegistryValueKind.DWord => "REG_DWORD",
|
||||
RegistryValueKind.QWord => "REG_QWORD",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(valueName)),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,173 @@
|
|||
// 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.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Classes;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Helper;
|
||||
using Microsoft.PowerToys.Run.Plugin.Registry.Properties;
|
||||
using Wox.Plugin;
|
||||
|
||||
[assembly: InternalsVisibleTo("Microsoft.PowerToys.Run.Plugin.Registry.UnitTests")]
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry
|
||||
{
|
||||
/// <summary>
|
||||
/// Main class of this plugin that implement all used interfaces
|
||||
/// </summary>
|
||||
public class Main : IPlugin, IContextMenu, IPluginI18n, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of this assembly
|
||||
/// </summary>
|
||||
private readonly string _assemblyName;
|
||||
|
||||
/// <summary>
|
||||
/// The initial context for this plugin (contains API and meta-data)
|
||||
/// </summary>
|
||||
private PluginInitContext? _context;
|
||||
|
||||
/// <summary>
|
||||
/// The path to the icon for each result
|
||||
/// </summary>
|
||||
private string _defaultIconPath;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate that the plugin is disposed
|
||||
/// </summary>
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Main"/> class.
|
||||
/// </summary>
|
||||
public Main()
|
||||
{
|
||||
_assemblyName = Assembly.GetExecutingAssembly().GetName().Name ?? GetTranslatedPluginTitle();
|
||||
_defaultIconPath = "Images/reg.light.png";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the plugin with the given <see cref="PluginInitContext"/>
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="PluginInitContext"/> for this plugin</param>
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
_context.API.ThemeChanged += OnThemeChanged;
|
||||
UpdateIconPath(_context.API.GetCurrentTheme());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a filtered list, based on the given query
|
||||
/// </summary>
|
||||
/// <param name="query">The query to filter the list</param>
|
||||
/// <returns>A filtered list, can be empty when nothing was found</returns>
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
if (query?.Search is null)
|
||||
{
|
||||
return new List<Result>(0);
|
||||
}
|
||||
|
||||
var searchForValueName = QueryHelper.GetQueryParts(query.Search, out var queryKey, out var queryValueName);
|
||||
|
||||
var (baseKeyList, subKey) = RegistryHelper.GetRegistryBaseKey(queryKey);
|
||||
if (baseKeyList is null)
|
||||
{
|
||||
// no base key found
|
||||
return ResultHelper.GetResultList(RegistryHelper.GetAllBaseKeys(), _defaultIconPath);
|
||||
}
|
||||
else if (baseKeyList.Count() > 1)
|
||||
{
|
||||
// more than one base key was found -> show results
|
||||
return ResultHelper.GetResultList(baseKeyList.Select(found => new RegistryEntry(found)), _defaultIconPath);
|
||||
}
|
||||
|
||||
// only one base key was found -> start search for the sub-key
|
||||
var list = RegistryHelper.SearchForSubKey(baseKeyList.First(), subKey);
|
||||
|
||||
// when only one sub-key was found and a user search for values ("\\")
|
||||
// show the filtered list of values of one sub-key
|
||||
if (searchForValueName && list.Count == 1)
|
||||
{
|
||||
return ResultHelper.GetValuesFromKey(list.First().Key, _defaultIconPath, queryValueName);
|
||||
}
|
||||
|
||||
return ResultHelper.GetResultList(list, _defaultIconPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list context menu entries for a given <see cref="Result"/> (shown at the right side of the result)
|
||||
/// </summary>
|
||||
/// <param name="selectedResult">The <see cref="Result"/> for the list with context menu entries</param>
|
||||
/// <returns>A list context menu entries</returns>
|
||||
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
return ContextMenuHelper.GetContextMenu(selectedResult, _assemblyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change all theme-based elements (typical called when the plugin theme has changed)
|
||||
/// </summary>
|
||||
/// <param name="oldtheme">The old <see cref="Theme"/></param>
|
||||
/// <param name="newTheme">The new <see cref="Theme"/></param>
|
||||
private void OnThemeChanged(Theme oldtheme, Theme newTheme)
|
||||
{
|
||||
UpdateIconPath(newTheme);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update all icons (typical called when the plugin theme has changed)
|
||||
/// </summary>
|
||||
/// <param name="theme">The new <see cref="Theme"/> for the icons</param>
|
||||
private void UpdateIconPath(Theme theme)
|
||||
{
|
||||
_defaultIconPath = theme == Theme.Light || theme == Theme.HighContrastWhite
|
||||
? "Images/reg.light.png"
|
||||
: "Images/reg.dark.png";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method for <see cref="Dispose"/> that dispose additional objects and events form the plugin itself
|
||||
/// </summary>
|
||||
/// <param name="disposing">Indicate that the plugin is disposed</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed || !disposing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(_context is null))
|
||||
{
|
||||
_context.API.ThemeChanged -= OnThemeChanged;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return Resources.PluginTitle;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return Resources.PluginDescription;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<RootNamespace>Microsoft.PowerToys.Run.Plugin.Registry</RootNamespace>
|
||||
<AssemblyName>Microsoft.PowerToys.Run.Plugin.Registry</AssemblyName>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<Platforms>x64</Platforms>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Optimize>false</Optimize>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Languages\**" />
|
||||
<EmbeddedResource Remove="Languages\**" />
|
||||
<None Remove="Languages\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\..\codeAnalysis\GlobalSuppressions.cs">
|
||||
<Link>GlobalSuppressions.cs</Link>
|
||||
</Compile>
|
||||
<AdditionalFiles Include="..\..\..\..\codeAnalysis\StyleCop.json">
|
||||
<Link>StyleCop.json</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Wox.Infrastructure\Wox.Infrastructure.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="plugin.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Images\reg.dark.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Images\reg.light.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
225
src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Registry/Properties/Resources.Designer.cs
generated
Normal file
225
src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Registry/Properties/Resources.Designer.cs
generated
Normal file
|
@ -0,0 +1,225 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Registry.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.PowerToys.Run.Plugin.Registry.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy key name (path).
|
||||
/// </summary>
|
||||
internal static string CopyKeyNamePath {
|
||||
get {
|
||||
return ResourceManager.GetString("CopyKeyNamePath", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy value data.
|
||||
/// </summary>
|
||||
internal static string CopyValueData {
|
||||
get {
|
||||
return ResourceManager.GetString("CopyValueData", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy value name.
|
||||
/// </summary>
|
||||
internal static string CopyValueName {
|
||||
get {
|
||||
return ResourceManager.GetString("CopyValueName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Key name:.
|
||||
/// </summary>
|
||||
internal static string KeyName {
|
||||
get {
|
||||
return ResourceManager.GetString("KeyName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Name:.
|
||||
/// </summary>
|
||||
internal static string Name {
|
||||
get {
|
||||
return ResourceManager.GetString("Name", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You do not have enough rights to open the Windows registry editor.
|
||||
/// </summary>
|
||||
internal static string OpenInRegistryEditorAccessExceptionText {
|
||||
get {
|
||||
return ResourceManager.GetString("OpenInRegistryEditorAccessExceptionText", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error on open registry editor.
|
||||
/// </summary>
|
||||
internal static string OpenInRegistryEditorAccessExceptionTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("OpenInRegistryEditorAccessExceptionTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Open key in registry editor.
|
||||
/// </summary>
|
||||
internal static string OpenKeyInRegistryEditor {
|
||||
get {
|
||||
return ResourceManager.GetString("OpenKeyInRegistryEditor", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search inside the Windows Registry.
|
||||
/// </summary>
|
||||
internal static string PluginDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("PluginDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Registry Plugin.
|
||||
/// </summary>
|
||||
internal static string PluginTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("PluginTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Registry key.
|
||||
/// </summary>
|
||||
internal static string RegistryKey {
|
||||
get {
|
||||
return ResourceManager.GetString("RegistryKey", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Registry value.
|
||||
/// </summary>
|
||||
internal static string RegistryValue {
|
||||
get {
|
||||
return ResourceManager.GetString("RegistryValue", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to No data type.
|
||||
/// </summary>
|
||||
internal static string RegistryValueKindNone {
|
||||
get {
|
||||
return ResourceManager.GetString("RegistryValueKindNone", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unsupported data type.
|
||||
/// </summary>
|
||||
internal static string RegistryValueKindUnknown {
|
||||
get {
|
||||
return ResourceManager.GetString("RegistryValueKindUnknown", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Subkeys:.
|
||||
/// </summary>
|
||||
internal static string SubKeys {
|
||||
get {
|
||||
return ResourceManager.GetString("SubKeys", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Type:.
|
||||
/// </summary>
|
||||
internal static string Type {
|
||||
get {
|
||||
return ResourceManager.GetString("Type", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Value:.
|
||||
/// </summary>
|
||||
internal static string Value {
|
||||
get {
|
||||
return ResourceManager.GetString("Value", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Values:.
|
||||
/// </summary>
|
||||
internal static string Values {
|
||||
get {
|
||||
return ResourceManager.GetString("Values", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="PluginTitle" xml:space="preserve">
|
||||
<value>Registry Plugin</value>
|
||||
</data>
|
||||
<data name="PluginDescription" xml:space="preserve">
|
||||
<value>Search inside the Windows Registry</value>
|
||||
<comment>"this built into Windows the OS. translate accordingly, https://docs.microsoft.com/de-de/troubleshoot/windows-server/performance/windows-registry-advanced-users is an example of it translated in German"</comment>
|
||||
</data>
|
||||
<data name="CopyKeyNamePath" xml:space="preserve">
|
||||
<value>Copy key name (path)</value>
|
||||
<comment>'The maximum size of a key name is 255 characters.'</comment>
|
||||
</data>
|
||||
<data name="KeyName" xml:space="preserve">
|
||||
<value>Key name:</value>
|
||||
<comment>'The maximum size of a key name is 255 characters.'</comment>
|
||||
</data>
|
||||
<data name="Name" xml:space="preserve">
|
||||
<value>Name:</value>
|
||||
</data>
|
||||
<data name="CopyValueName" xml:space="preserve">
|
||||
<value>Copy value name</value>
|
||||
</data>
|
||||
<data name="OpenKeyInRegistryEditor" xml:space="preserve">
|
||||
<value>Open key in registry editor</value>
|
||||
<comment>"registry editor" is the name of the OS built-in application</comment>
|
||||
</data>
|
||||
<data name="OpenInRegistryEditorAccessExceptionText" xml:space="preserve">
|
||||
<value>You do not have enough rights to open the Windows registry editor</value>
|
||||
<comment>"registry editor" is the name of the OS built-in application </comment>
|
||||
</data>
|
||||
<data name="OpenInRegistryEditorAccessExceptionTitle" xml:space="preserve">
|
||||
<value>Error on open registry editor</value>
|
||||
<comment>"registry editor" is the name of the OS built-in application</comment>
|
||||
</data>
|
||||
<data name="SubKeys" xml:space="preserve">
|
||||
<value>Subkeys:</value>
|
||||
</data>
|
||||
<data name="Values" xml:space="preserve">
|
||||
<value>Values:</value>
|
||||
</data>
|
||||
<data name="RegistryKey" xml:space="preserve">
|
||||
<value>Registry key</value>
|
||||
</data>
|
||||
<data name="RegistryValue" xml:space="preserve">
|
||||
<value>Registry value</value>
|
||||
</data>
|
||||
<data name="Type" xml:space="preserve">
|
||||
<value>Type:</value>
|
||||
<comment>See https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types for proper context of how to translate 'type'</comment>
|
||||
</data>
|
||||
<data name="Value" xml:space="preserve">
|
||||
<value>Value:</value>
|
||||
<comment>See https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types for proper context of how to translate 'value'</comment>
|
||||
</data>
|
||||
<data name="RegistryValueKindNone" xml:space="preserve">
|
||||
<value>No data type</value>
|
||||
</data>
|
||||
<data name="RegistryValueKindUnknown" xml:space="preserve">
|
||||
<value>Unsupported data type</value>
|
||||
</data>
|
||||
<data name="CopyValueData" xml:space="preserve">
|
||||
<value>Copy value data</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"ID": "303417D927BF4C97BCFFC78A123BE0C8",
|
||||
"ActionKeyword": ":",
|
||||
"Name": "Registry",
|
||||
"Description": "Search inside the Windows Registry",
|
||||
"Author": "TobiasSekan",
|
||||
"Version": "1.0.0",
|
||||
"Language": "csharp",
|
||||
"Website": "https://aka.ms/powertoys",
|
||||
"ExecuteFileName": "Microsoft.PowerToys.Run.Plugin.Registry.dll",
|
||||
"IcoPath": "Images\\reg.dark.png"
|
||||
}
|
Loading…
Reference in a new issue