Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Adjust comment and add tests.
  • Loading branch information
huoyaoyuan committed Jul 12, 2023
commit ec456762f6f7a48a28bb1e5dd14a9bf50656bbc2
Original file line number Diff line number Diff line change
Expand Up @@ -334,22 +334,23 @@ public void DeleteSubKeyTree(string subkey, bool throwOnMissingSubKey)

subkey = FixupName(subkey); // Fixup multiple slashes to a single slash

RegistryKey? key = InternalOpenSubKeyWithoutSecurityChecks(subkey, false);
// If the key has values, it must be opened with KEY_SET_VALUE,
// or RegDeleteTree will fail with ERROR_ACCESS_DENIED.

RegistryKey? key = InternalOpenSubKeyWithoutSecurityChecks(subkey, true);
if (key != null)
{
using (key)
{
// The access requirement of RegDeleteTree is different with old implementation.
// Open a new handle to the subkey to restore old behavior.
int ret = Interop.Advapi32.RegDeleteTree(key._hkey, string.Empty);
if (ret != 0)
{
Win32Error(ret, null);
}

// RegDeleteTree only delete subkeys and values of the key
// if subkey is null.
// Also delete the key.
// RegDeleteTree doesn't self-delete when lpSubKey is empty.
// Manually delete the key to restore old behavior.

ret = Interop.Advapi32.RegDeleteKeyEx(key._hkey, string.Empty, (int)_regView, 0);
if (ret != 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using System.Linq;
using System.Reflection;
using Xunit;

namespace Microsoft.Win32.RegistryTests
Expand Down Expand Up @@ -49,6 +48,38 @@ public void SelfDeleteTest()

Assert.Null(TestRegistryKey.OpenSubKey(TestRegistryKeyName));
}

[Fact]
public void SelfDeleteWithValuesTest()
{
using (var rk = TestRegistryKey.CreateSubKey(TestRegistryKeyName))
{
rk.SetValue("VAL", "Dummy", RegistryValueKind.String);
rk.SetDefaultValue("Default");
using RegistryKey created = rk.CreateSubKey(TestRegistryKeyName);
created.SetValue("Value", 42, RegistryValueKind.DWord);
rk.DeleteSubKeyTree("");
}

Assert.Null(TestRegistryKey.OpenSubKey(TestRegistryKeyName));
}

[Fact]
public void SelfDeleteWithValuesTest_AnotherHandlePresent()
{
using (var rk = TestRegistryKey.CreateSubKey(TestRegistryKeyName))
{
rk.SetValue("VAL", "Dummy", RegistryValueKind.String);
rk.SetDefaultValue("Default");
using RegistryKey created = rk.CreateSubKey(TestRegistryKeyName);
created.SetValue("Value", 42, RegistryValueKind.DWord);

using var rk2 = TestRegistryKey.OpenSubKey(TestRegistryKeyName);
rk.DeleteSubKeyTree("");
}

Assert.Null(TestRegistryKey.OpenSubKey(TestRegistryKeyName));
}

[Fact]
public void DeleteSubKeyTreeTest()
Expand Down Expand Up @@ -85,6 +116,37 @@ public void DeleteSubKeyTreeTest2()
TestRegistryKey.DeleteSubKeyTree(TestRegistryKeyName);
Assert.Null(TestRegistryKey.OpenSubKey(TestRegistryKeyName));
}

[Fact]
public void DeleteSubKeyTreeTest3()
{
// [] Add in multiple subkeys and then delete the root key
string[] subKeyNames = Enumerable.Range(1, 9).Select(x => "BLAH_" + x.ToString()).ToArray();

using (RegistryKey rk = TestRegistryKey.CreateSubKey(TestRegistryKeyName))
{
foreach (var subKeyName in subKeyNames)
{
using RegistryKey rk2 = rk.CreateSubKey(subKeyName);
Assert.NotNull(rk2);

using RegistryKey rk3 = rk2.CreateSubKey("Test");
Assert.NotNull(rk3);
}

Assert.Equal(subKeyNames, rk.GetSubKeyNames());

// Add multiple values to the key being deleted
foreach (int i in Enumerable.Range(1, 9))
{
rk.SetValue("STRVAL_" + i, i.ToString(), RegistryValueKind.String);
rk.SetValue("INTVAL_" + i, i, RegistryValueKind.DWord);
}
}

TestRegistryKey.DeleteSubKeyTree(TestRegistryKeyName);
Assert.Null(TestRegistryKey.OpenSubKey(TestRegistryKeyName));
}

[Theory]
[MemberData(nameof(TestRegistrySubKeyNames))]
Expand Down