RegistryKey
Represents a key-level node in the Windows registry. This class is a registry encapsulation.
using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.AccessControl;
using System.Text;
namespace Microsoft.Win32
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public sealed class RegistryKey : MarshalByRefObject, IDisposable
{
[Flags]
private enum StateFlags
{
Dirty = 1,
SystemKey = 2,
WriteAccess = 4,
PerfData = 8
}
private static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(-2147483648);
private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(-2147483647);
private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(-2147483646);
private static readonly IntPtr HKEY_USERS = new IntPtr(-2147483645);
private static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(-2147483644);
private static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(-2147483643);
private static readonly string[] s_hkeyNames = new string[6] {
"HKEY_CLASSES_ROOT",
"HKEY_CURRENT_USER",
"HKEY_LOCAL_MACHINE",
"HKEY_USERS",
"HKEY_PERFORMANCE_DATA",
"HKEY_CURRENT_CONFIG"
};
private const int MaxKeyLength = 255;
private const int MaxValueLength = 16383;
private volatile SafeRegistryHandle _hkey;
private volatile string _keyName;
private readonly bool _remoteKey;
private volatile StateFlags _state;
private volatile RegistryKeyPermissionCheck _checkMode;
private readonly RegistryView _regView;
public int SubKeyCount {
get {
EnsureNotDisposed();
return InternalSubKeyCountCore();
}
}
public RegistryView View {
get {
EnsureNotDisposed();
return _regView;
}
}
public SafeRegistryHandle Handle {
get {
EnsureNotDisposed();
if (!IsSystemKey())
return _hkey;
return SystemKeyHandle;
}
}
public int ValueCount {
get {
EnsureNotDisposed();
return InternalValueCountCore();
}
}
public string Name {
get {
EnsureNotDisposed();
return _keyName;
}
}
private SafeRegistryHandle SystemKeyHandle {
get {
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
}
private RegistryKey(SafeRegistryHandle hkey, bool writable, RegistryView view)
: this(hkey, writable, false, false, false, view)
{
}
private RegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey, bool remoteKey, bool isPerfData, RegistryView view)
{
ValidateKeyView(view);
_hkey = hkey;
_keyName = "";
_remoteKey = remoteKey;
_regView = view;
if (systemkey)
_state |= StateFlags.SystemKey;
if (writable)
_state |= StateFlags.WriteAccess;
if (isPerfData)
_state |= StateFlags.PerfData;
}
public void Flush()
{
FlushCore();
}
public void Close()
{
Dispose();
}
public void Dispose()
{
if (_hkey != null) {
if (!IsSystemKey())
try {
_hkey.Dispose();
} catch (IOException) {
} finally {
_hkey = null;
}
else if (IsPerfDataKey()) {
ClosePerfDataKey();
}
}
}
public RegistryKey CreateSubKey(string subkey)
{
return CreateSubKey(subkey, _checkMode);
}
public RegistryKey CreateSubKey(string subkey, bool writable)
{
return CreateSubKey(subkey, (!writable) ? RegistryKeyPermissionCheck.ReadSubTree : RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None);
}
public RegistryKey CreateSubKey(string subkey, bool writable, RegistryOptions options)
{
return CreateSubKey(subkey, (!writable) ? RegistryKeyPermissionCheck.ReadSubTree : RegistryKeyPermissionCheck.ReadWriteSubTree, options);
}
public RegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck)
{
return CreateSubKey(subkey, permissionCheck, RegistryOptions.None);
}
public RegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions, [System.Runtime.CompilerServices.Nullable(2)] RegistrySecurity registrySecurity)
{
return CreateSubKey(subkey, permissionCheck, registryOptions);
}
public RegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck, [System.Runtime.CompilerServices.Nullable(2)] RegistrySecurity registrySecurity)
{
return CreateSubKey(subkey, permissionCheck, RegistryOptions.None);
}
public RegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions)
{
ValidateKeyOptions(registryOptions);
ValidateKeyName(subkey);
ValidateKeyMode(permissionCheck);
EnsureWriteable();
subkey = FixupName(subkey);
if (!_remoteKey) {
RegistryKey registryKey = InternalOpenSubKeyWithoutSecurityChecks(subkey, permissionCheck != RegistryKeyPermissionCheck.ReadSubTree);
if (registryKey != null) {
registryKey._checkMode = permissionCheck;
return registryKey;
}
}
return CreateSubKeyInternalCore(subkey, permissionCheck, registryOptions);
}
public void DeleteSubKey(string subkey)
{
DeleteSubKey(subkey, true);
}
public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
{
ValidateKeyName(subkey);
EnsureWriteable();
subkey = FixupName(subkey);
RegistryKey registryKey = InternalOpenSubKeyWithoutSecurityChecks(subkey, false);
if (registryKey != null) {
using (registryKey) {
if (registryKey.SubKeyCount > 0)
throw new InvalidOperationException(System.SR.InvalidOperation_RegRemoveSubKey);
}
DeleteSubKeyCore(subkey, throwOnMissingSubKey);
} else if (throwOnMissingSubKey) {
throw new ArgumentException(System.SR.Arg_RegSubKeyAbsent);
}
}
public void DeleteSubKeyTree(string subkey)
{
DeleteSubKeyTree(subkey, true);
}
public void DeleteSubKeyTree(string subkey, bool throwOnMissingSubKey)
{
ValidateKeyName(subkey);
if (subkey.Length == 0 && IsSystemKey())
throw new ArgumentException(System.SR.Arg_RegKeyDelHive);
EnsureWriteable();
subkey = FixupName(subkey);
RegistryKey registryKey = InternalOpenSubKeyWithoutSecurityChecks(subkey, true);
if (registryKey != null) {
using (registryKey) {
if (registryKey.SubKeyCount > 0) {
string[] subKeyNames = registryKey.GetSubKeyNames();
for (int i = 0; i < subKeyNames.Length; i++) {
registryKey.DeleteSubKeyTreeInternal(subKeyNames[i]);
}
}
}
DeleteSubKeyTreeCore(subkey);
} else if (throwOnMissingSubKey) {
throw new ArgumentException(System.SR.Arg_RegSubKeyAbsent);
}
}
private void DeleteSubKeyTreeInternal(string subkey)
{
RegistryKey registryKey = InternalOpenSubKeyWithoutSecurityChecks(subkey, true);
if (registryKey != null) {
using (registryKey) {
if (registryKey.SubKeyCount > 0) {
string[] subKeyNames = registryKey.GetSubKeyNames();
for (int i = 0; i < subKeyNames.Length; i++) {
registryKey.DeleteSubKeyTreeInternal(subKeyNames[i]);
}
}
}
DeleteSubKeyTreeCore(subkey);
return;
}
throw new ArgumentException(System.SR.Arg_RegSubKeyAbsent);
}
public void DeleteValue(string name)
{
DeleteValue(name, true);
}
public void DeleteValue(string name, bool throwOnMissingValue)
{
EnsureWriteable();
DeleteValueCore(name, throwOnMissingValue);
}
public static RegistryKey OpenBaseKey(RegistryHive hKey, RegistryView view)
{
ValidateKeyView(view);
return OpenBaseKeyCore(hKey, view);
}
public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey, string machineName)
{
return OpenRemoteBaseKey(hKey, machineName, RegistryView.Default);
}
public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey, string machineName, RegistryView view)
{
if (machineName == null)
throw new ArgumentNullException("machineName");
ValidateKeyView(view);
return OpenRemoteBaseKeyCore(hKey, machineName, view);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public RegistryKey OpenSubKey(string name)
{
return OpenSubKey(name, false);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public RegistryKey OpenSubKey(string name, bool writable)
{
ValidateKeyName(name);
EnsureNotDisposed();
name = FixupName(name);
return InternalOpenSubKeyCore(name, writable);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public RegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck)
{
ValidateKeyMode(permissionCheck);
return OpenSubKey(name, permissionCheck, (RegistryRights)GetRegistryKeyAccess(permissionCheck));
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public RegistryKey OpenSubKey(string name, RegistryRights rights)
{
return OpenSubKey(name, _checkMode, rights);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public RegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
{
ValidateKeyName(name);
ValidateKeyMode(permissionCheck);
ValidateKeyRights(rights);
EnsureNotDisposed();
name = FixupName(name);
return InternalOpenSubKeyCore(name, permissionCheck, (int)rights);
}
internal RegistryKey InternalOpenSubKeyWithoutSecurityChecks(string name, bool writable)
{
ValidateKeyName(name);
EnsureNotDisposed();
return InternalOpenSubKeyWithoutSecurityChecksCore(name, writable);
}
public RegistrySecurity GetAccessControl()
{
return GetAccessControl(AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
}
public RegistrySecurity GetAccessControl(AccessControlSections includeSections)
{
EnsureNotDisposed();
return new RegistrySecurity(Handle, Name, includeSections);
}
public void SetAccessControl(RegistrySecurity registrySecurity)
{
EnsureWriteable();
if (registrySecurity == null)
throw new ArgumentNullException("registrySecurity");
registrySecurity.Persist(Handle, Name);
}
public static RegistryKey FromHandle(SafeRegistryHandle handle)
{
return FromHandle(handle, RegistryView.Default);
}
public static RegistryKey FromHandle(SafeRegistryHandle handle, RegistryView view)
{
if (handle == null)
throw new ArgumentNullException("handle");
ValidateKeyView(view);
return new RegistryKey(handle, true, view);
}
public string[] GetSubKeyNames()
{
EnsureNotDisposed();
int subKeyCount = SubKeyCount;
if (subKeyCount <= 0)
return Array.Empty<string>();
return InternalGetSubKeyNamesCore(subKeyCount);
}
public string[] GetValueNames()
{
EnsureNotDisposed();
int valueCount = ValueCount;
if (valueCount <= 0)
return Array.Empty<string>();
return GetValueNamesCore(valueCount);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public object GetValue(string name)
{
return InternalGetValue(name, null, false);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public object GetValue(string name, object defaultValue)
{
return InternalGetValue(name, defaultValue, false);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public object GetValue(string name, object defaultValue, RegistryValueOptions options)
{
if (options < RegistryValueOptions.None || options > RegistryValueOptions.DoNotExpandEnvironmentNames)
throw new ArgumentException(System.SR.Format(System.SR.Arg_EnumIllegalVal, (int)options), "options");
bool doNotExpand = options == RegistryValueOptions.DoNotExpandEnvironmentNames;
return InternalGetValue(name, defaultValue, doNotExpand);
}
private object InternalGetValue(string name, object defaultValue, bool doNotExpand)
{
EnsureNotDisposed();
return InternalGetValueCore(name, defaultValue, doNotExpand);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public RegistryValueKind GetValueKind(string name)
{
EnsureNotDisposed();
return GetValueKindCore(name);
}
public void SetValue([System.Runtime.CompilerServices.Nullable(2)] string name, object value)
{
SetValue(name, value, RegistryValueKind.Unknown);
}
public void SetValue([System.Runtime.CompilerServices.Nullable(2)] string name, object value, RegistryValueKind valueKind)
{
if (value == null)
throw new ArgumentNullException("value");
if (name != null && name.Length > 16383)
throw new ArgumentException(System.SR.Arg_RegValStrLenBug, "name");
if (!Enum.IsDefined(typeof(RegistryValueKind), valueKind))
throw new ArgumentException(System.SR.Arg_RegBadKeyKind, "valueKind");
EnsureWriteable();
if (valueKind == RegistryValueKind.Unknown)
valueKind = CalculateValueKind(value);
SetValueCore(name, value, valueKind);
}
private RegistryValueKind CalculateValueKind(object value)
{
if (value is int)
return RegistryValueKind.DWord;
if (value is Array) {
if (value is byte[])
return RegistryValueKind.Binary;
if (value is string[])
return RegistryValueKind.MultiString;
throw new ArgumentException(System.SR.Format(System.SR.Arg_RegSetBadArrType, value.GetType().Name));
}
return RegistryValueKind.String;
}
public override string ToString()
{
EnsureNotDisposed();
return _keyName;
}
private static string FixupName(string name)
{
if (name.IndexOf('\\') == -1)
return name;
StringBuilder stringBuilder = new StringBuilder(name);
FixupPath(stringBuilder);
int num = stringBuilder.Length - 1;
if (num >= 0 && stringBuilder[num] == '\\')
stringBuilder.Length = num;
return stringBuilder.ToString();
}
private static void FixupPath(StringBuilder path)
{
int length = path.Length;
bool flag = false;
char c = '';
for (int i = 1; i < length - 1; i++) {
if (path[i] == '\\') {
i++;
while (i < length && path[i] == '\\') {
path[i] = c;
i++;
flag = true;
}
}
}
if (flag) {
int i = 0;
int num = 0;
while (i < length) {
if (path[i] == c)
i++;
else {
path[num] = path[i];
i++;
num++;
}
}
path.Length += num - i;
}
}
private void EnsureNotDisposed()
{
if (_hkey == null)
throw new ObjectDisposedException(_keyName, System.SR.ObjectDisposed_RegKeyClosed);
}
private void EnsureWriteable()
{
EnsureNotDisposed();
if (!IsWritable())
throw new UnauthorizedAccessException(System.SR.UnauthorizedAccess_RegistryNoWrite);
}
private RegistryKeyPermissionCheck GetSubKeyPermissionCheck(bool subkeyWritable)
{
if (_checkMode == RegistryKeyPermissionCheck.Default)
return _checkMode;
if (subkeyWritable)
return RegistryKeyPermissionCheck.ReadWriteSubTree;
return RegistryKeyPermissionCheck.ReadSubTree;
}
private static void ValidateKeyName(string name)
{
if (name == null)
throw new ArgumentNullException("name");
int num = name.IndexOf("\\", StringComparison.OrdinalIgnoreCase);
int num2 = 0;
while (num != -1) {
if (num - num2 > 255)
throw new ArgumentException(System.SR.Arg_RegKeyStrLenBug, "name");
num2 = num + 1;
num = name.IndexOf("\\", num2, StringComparison.OrdinalIgnoreCase);
}
if (name.Length - num2 > 255)
throw new ArgumentException(System.SR.Arg_RegKeyStrLenBug, "name");
}
private static void ValidateKeyMode(RegistryKeyPermissionCheck mode)
{
if (mode < RegistryKeyPermissionCheck.Default || mode > RegistryKeyPermissionCheck.ReadWriteSubTree)
throw new ArgumentException(System.SR.Argument_InvalidRegistryKeyPermissionCheck, "mode");
}
private static void ValidateKeyOptions(RegistryOptions options)
{
if (options < RegistryOptions.None || options > RegistryOptions.Volatile)
throw new ArgumentException(System.SR.Argument_InvalidRegistryOptionsCheck, "options");
}
private static void ValidateKeyView(RegistryView view)
{
if (view != 0 && view != RegistryView.Registry32 && view != RegistryView.Registry64)
throw new ArgumentException(System.SR.Argument_InvalidRegistryViewCheck, "view");
}
private static void ValidateKeyRights(RegistryRights rights)
{
if ((rights & ~(RegistryRights.QueryValues | RegistryRights.SetValue | RegistryRights.CreateSubKey | RegistryRights.EnumerateSubKeys | RegistryRights.Notify | RegistryRights.CreateLink | RegistryRights.Delete | RegistryRights.ReadPermissions | RegistryRights.ChangePermissions | RegistryRights.TakeOwnership)) != 0)
throw new SecurityException(System.SR.Security_RegistryPermission);
}
private bool IsDirty()
{
return (_state & StateFlags.Dirty) != (StateFlags)0;
}
private bool IsSystemKey()
{
return (_state & StateFlags.SystemKey) != (StateFlags)0;
}
private bool IsWritable()
{
return (_state & StateFlags.WriteAccess) != (StateFlags)0;
}
private bool IsPerfDataKey()
{
return (_state & StateFlags.PerfData) != (StateFlags)0;
}
private void SetDirty()
{
_state |= StateFlags.Dirty;
}
private void ClosePerfDataKey()
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private void FlushCore()
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private RegistryKey CreateSubKeyInternalCore(string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private void DeleteSubKeyCore(string subkey, bool throwOnMissingSubKey)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private void DeleteSubKeyTreeCore(string subkey)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private void DeleteValueCore(string name, bool throwOnMissingValue)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private static RegistryKey OpenBaseKeyCore(RegistryHive hKey, RegistryView view)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private static RegistryKey OpenRemoteBaseKeyCore(RegistryHive hKey, string machineName, RegistryView view)
{
throw new PlatformNotSupportedException(System.SR.Security_RegistryPermission);
}
private RegistryKey InternalOpenSubKeyCore(string name, RegistryKeyPermissionCheck permissionCheck, int rights)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private RegistryKey InternalOpenSubKeyCore(string name, bool writable)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
internal RegistryKey InternalOpenSubKeyWithoutSecurityChecksCore(string name, bool writable)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private int InternalSubKeyCountCore()
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private string[] InternalGetSubKeyNamesCore(int subkeys)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private int InternalValueCountCore()
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private string[] GetValueNamesCore(int values)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private object InternalGetValueCore(string name, object defaultValue, bool doNotExpand)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private RegistryValueKind GetValueKindCore(string name)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private void SetValueCore(string name, object value, RegistryValueKind valueKind)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private static int GetRegistryKeyAccess(bool isWritable)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
private static int GetRegistryKeyAccess(RegistryKeyPermissionCheck mode)
{
throw new PlatformNotSupportedException(System.SR.PlatformNotSupported_Registry);
}
}
}