-
Notifications
You must be signed in to change notification settings - Fork 414
Expand file tree
/
Copy pathRegistryService.cs
More file actions
104 lines (91 loc) · 3.45 KB
/
RegistryService.cs
File metadata and controls
104 lines (91 loc) · 3.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information.
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
namespace Microsoft.VisualStudio.ProjectSystem.VS.Utilities;
/// <summary>
/// Provides access to the Windows registry.
/// </summary>
[Export(typeof(IRegistry))]
internal class RegistryService : IRegistry
{
/// <inheritdoc/>
public string? GetValue(RegistryHive hive, RegistryView view, string subKeyPath, string valueName)
{
using RegistryKey? subKey = OpenSubKey(hive, view, subKeyPath);
return subKey?.GetValue(valueName) as string;
}
/// <inheritdoc/>
public string[] GetValueNames(RegistryHive hive, RegistryView view, string subKeyPath)
{
using RegistryKey? subKey = OpenSubKey(hive, view, subKeyPath);
return subKey is null
? []
: GetValueNames(subKey);
}
private static RegistryKey? OpenSubKey(RegistryHive hive, RegistryView view, string subKeyPath)
{
try
{
using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, view);
return baseKey.OpenSubKey(subKeyPath);
}
catch (Exception ex) when (ex.IsCatchable())
{
// Return null on catchable registry access errors
return null;
}
}
/// <summary>
/// Functional equivalent of <see cref="RegistryKey.GetValueNames"/>. Implemented
/// as net framework implementation of this method allocates 32 KB buffer on every
/// invocation.
/// </summary>
private static string[] GetValueNames(RegistryKey key)
{
List<string> names = new List<string>();
char[] name = new char[128];
int nameLength = name.Length;
SafeRegistryHandle handle = key.Handle;
int enumIndex = 0;
int result = NativeMethods.RegEnumValue(handle, enumIndex, name, ref nameLength, IntPtr.Zero, null, null, null);
while (result != NativeMethods.ERROR_NO_MORE_ITEMS)
{
if (result == NativeMethods.ERROR_SUCCESS)
{
names.Add(new string(name, 0, nameLength));
enumIndex++;
}
else if (result == NativeMethods.ERROR_MORE_DATA)
{
// Buffer was too small, increase it's size and call again for the same index
name = new char[name.Length * 2];
}
else
{
// Unknown error, skip this item
enumIndex++;
}
// Always set the name length back to the buffer size
nameLength = name.Length;
result = NativeMethods.RegEnumValue(handle, enumIndex, name, ref nameLength, IntPtr.Zero, null, null, null);
}
return names.ToArray();
}
private static class NativeMethods
{
internal const int ERROR_SUCCESS = 0;
internal const int ERROR_MORE_DATA = 234;
internal const int ERROR_NO_MORE_ITEMS = 259;
[DllImport("advapi32.dll")]
internal static extern int RegEnumValue(
SafeRegistryHandle hKey,
int dwIndex,
[Out] char[] lpValueName,
ref int lpcbValueName,
IntPtr lpReserved_MustBeZero,
int[]? lpType,
byte[]? lpData,
int[]? lpcbData);
}
}