Skip to content

Commit cbfc549

Browse files
authored
Improve performance of RegistryKey.GetValue (#66918)
Reduces typical number of syscalls as well as avoids allocation (or uses the ArrayPool otherwise). Also updates Corelib's copy of RegistryKey to match (with things like perf key support removed).
1 parent 02ee890 commit cbfc549

File tree

7 files changed

+333
-412
lines changed

7 files changed

+333
-412
lines changed

src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,12 @@ internal static partial int RegQueryValueEx(
2222
ref int lpcbData);
2323

2424
[LibraryImport(Libraries.Advapi32, EntryPoint = "RegQueryValueExW", StringMarshalling = StringMarshalling.Utf16)]
25-
internal static partial int RegQueryValueEx(
26-
SafeRegistryHandle hKey,
27-
string? lpValueName,
28-
int[]? lpReserved,
29-
ref int lpType,
30-
ref int lpData,
31-
ref int lpcbData);
32-
33-
[LibraryImport(Libraries.Advapi32, EntryPoint = "RegQueryValueExW", StringMarshalling = StringMarshalling.Utf16)]
34-
internal static partial int RegQueryValueEx(
35-
SafeRegistryHandle hKey,
36-
string? lpValueName,
37-
int[]? lpReserved,
38-
ref int lpType,
39-
ref long lpData,
40-
ref int lpcbData);
41-
42-
[LibraryImport(Libraries.Advapi32, EntryPoint = "RegQueryValueExW", StringMarshalling = StringMarshalling.Utf16)]
43-
internal static partial int RegQueryValueEx(
25+
internal static unsafe partial int RegQueryValueEx(
4426
SafeRegistryHandle hKey,
4527
string? lpValueName,
46-
int[]? lpReserved,
47-
ref int lpType,
48-
[Out] char[]? lpData,
49-
ref int lpcbData);
28+
int* lpReserved,
29+
int* lpType,
30+
byte* lpData,
31+
uint* lpcbData);
5032
}
5133
}

src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.Windows.cs

Lines changed: 163 additions & 204 deletions
Large diffs are not rendered by default.

src/libraries/Microsoft.Win32.Registry/src/Resources/Strings.resx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<root>
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<root>
23
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
34
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
45
<xsd:element name="root" msdata:IsDataSet="true">
@@ -84,8 +85,8 @@
8485
<data name="Arg_RegBadKeyKind" xml:space="preserve">
8586
<value>The specified RegistryValueKind is an invalid value.</value>
8687
</data>
87-
<data name="Arg_RegGetOverflowBug" xml:space="preserve">
88-
<value>RegistryKey.GetValue does not allow a String that has a length greater than Int32.MaxValue.</value>
88+
<data name="Arg_RegValueTooLarge" xml:space="preserve">
89+
<value>RegistryKey.GetValue does not support values with more than Int32.MaxValue bytes.</value>
8990
</data>
9091
<data name="Arg_RegSetMismatchedKind" xml:space="preserve">
9192
<value>The type of the value object did not match the specified RegistryValueKind or the object could not be properly converted.</value>
@@ -135,4 +136,4 @@
135136
<data name="UnauthorizedAccess_RegistryNoWrite" xml:space="preserve">
136137
<value>Cannot write to the registry key.</value>
137138
</data>
138-
</root>
139+
</root>

src/libraries/Microsoft.Win32.Registry/tests/RegistryKey/RegistryKey_GetValue_CorruptData.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,13 @@ public void ReadRegMultiSzLackingFinalNullTerminatorCorrectly()
4444
}
4545

4646
[Theory]
47-
[InlineData(RegistryValueKind.String, new byte[] { 6, 5, 6 })]
48-
[InlineData(RegistryValueKind.ExpandString, new byte[] { 6, 5, 6 })]
49-
[InlineData(RegistryValueKind.MultiString, new byte[] { 6, 5, 6, 0, 0 })]
50-
public void RegSzOddByteLength(RegistryValueKind kind, byte[] contents)
47+
[InlineData(RegistryValueKind.String, new byte[] { 6, 5, 6 }, "\u0506")]
48+
[InlineData(RegistryValueKind.ExpandString, new byte[] { 6, 5, 6 }, "\u0506")]
49+
[InlineData(RegistryValueKind.MultiString, new byte[] { 6, 5, 6 }, "\u0506")]
50+
[InlineData(RegistryValueKind.String, new byte[] { 6, 5, 6, 0, 0 }, "\u0506\u0006")]
51+
[InlineData(RegistryValueKind.ExpandString, new byte[] { 6, 5, 6, 0, 0 }, "\u0506\u0006")]
52+
[InlineData(RegistryValueKind.MultiString, new byte[] { 6, 5, 6, 0, 0 }, "\u0506\u0006")]
53+
public void RegSzOddByteLength(RegistryValueKind kind, byte[] contents, string expected)
5154
{
5255
const string TestValueName = "CorruptData2";
5356

@@ -73,9 +76,7 @@ public void RegSzOddByteLength(RegistryValueKind kind, byte[] contents)
7376
s = (string)o;
7477
}
7578

76-
Assert.Equal(2, s.Length);
77-
Assert.Equal(0x506, s[0]);
78-
Assert.Equal(0x6, s[1]);
79+
Assert.Equal(expected, s);
7980
}
8081
finally
8182
{

src/libraries/Microsoft.Win32.Registry/tests/RegistryKey/RegistryKey_GetValue_str.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,12 @@ public void GetStringArrayTest()
8686
Assert.Equal(expected, (string[])TestRegistryKey.GetValue(valueName));
8787
TestRegistryKey.DeleteValue(valueName);
8888
}
89+
90+
[Fact]
91+
public void GetPerformanceKeyValue()
92+
{
93+
string[] counterNames = (string[])Registry.PerformanceData.GetValue("Counter");
94+
Assert.NotEmpty(counterNames);
95+
}
8996
}
9097
}

0 commit comments

Comments
 (0)