summaryrefslogtreecommitdiff
path: root/src/System.Private.CoreLib
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2018-09-20 14:14:48 -0700
committerGitHub <noreply@github.com>2018-09-20 14:14:48 -0700
commit4ca5cd260a1c04f74961faccfad3200fe865a249 (patch)
tree539038626f286075d6942d3ca75a7d887c2b2456 /src/System.Private.CoreLib
parent0f4ecd9ccc1c7bad32d7ec8eb8bb335f67cfd432 (diff)
downloadcoreclr-4ca5cd260a1c04f74961faccfad3200fe865a249.tar.gz
coreclr-4ca5cd260a1c04f74961faccfad3200fe865a249.tar.bz2
coreclr-4ca5cd260a1c04f74961faccfad3200fe865a249.zip
Move RegistryKey to shared CoreLib partition (#20067)
* Move RegistryKey to shared CoreLib partition - Cut down RegistryKey to just what CoreLib needs. I went back and forth on whether to share the corefx implementation with ifdefs or not. I have choosen to duplicate it at the end. The ifdefs were either too complex or there was too much cruft left behind that the IL linker was not able to remove. - Move the internal CoreLib implementation of Registry to Internal.Win32 namespace to ensure that it is not confused with the public standlone one Fixes #10741 and #17899
Diffstat (limited to 'src/System.Private.CoreLib')
-rw-r--r--src/System.Private.CoreLib/Resources/Strings.resx27
-rw-r--r--src/System.Private.CoreLib/System.Private.CoreLib.csproj1
-rw-r--r--src/System.Private.CoreLib/shared/Internal/Win32/RegistryKey.cs485
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumValue.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegFlushKey.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryInfoKey.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs15
-rw-r--r--src/System.Private.CoreLib/shared/Microsoft/Win32/Registry.cs106
-rw-r--r--src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryHive.cs24
-rw-r--r--src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryOptions.cs20
-rw-r--r--src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueKind.cs23
-rw-r--r--src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueOptions.cs20
-rw-r--r--src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryView.cs20
-rw-r--r--src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.Windows.cs5
-rw-r--r--src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.cs5
-rw-r--r--src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems8
-rw-r--r--src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs9
-rw-r--r--src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs4
-rw-r--r--src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs2
-rw-r--r--src/System.Private.CoreLib/shared/System/Security/AccessControl/RegistryRights.cs42
-rw-r--r--src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs2
-rw-r--r--src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.cs1137
-rw-r--r--src/System.Private.CoreLib/src/System/Environment.cs31
29 files changed, 564 insertions, 1458 deletions
diff --git a/src/System.Private.CoreLib/Resources/Strings.resx b/src/System.Private.CoreLib/Resources/Strings.resx
index 403e5fc0c8..5d70c86beb 100644
--- a/src/System.Private.CoreLib/Resources/Strings.resx
+++ b/src/System.Private.CoreLib/Resources/Strings.resx
@@ -682,39 +682,18 @@
<data name="Arg_RanksAndBounds" xml:space="preserve">
<value>Number of lengths and lowerBounds must match.</value>
</data>
- <data name="Arg_RegBadKeyKind" xml:space="preserve">
- <value>The specified RegistryValueKind is an invalid value.</value>
- </data>
<data name="Arg_RegGetOverflowBug" xml:space="preserve">
<value>RegistryKey.GetValue does not allow a String that has a length greater than Int32.MaxValue.</value>
</data>
- <data name="Arg_RegInvalidKeyName" xml:space="preserve">
- <value>Registry key name must start with a valid base key name.</value>
- </data>
<data name="Arg_RegKeyNotFound" xml:space="preserve">
<value>The specified registry key does not exist.</value>
</data>
- <data name="Arg_RegKeyStrLenBug" xml:space="preserve">
- <value>Registry key names should not be greater than 255 characters.</value>
- </data>
- <data name="Arg_RegSetBadArrType" xml:space="preserve">
- <value>RegistryKey.SetValue does not support arrays of type '{0}'. Only Byte[] and String[] are supported.</value>
- </data>
- <data name="Arg_RegSetMismatchedKind" xml:space="preserve">
- <value>The type of the value object did not match the specified RegistryValueKind or the object could not be properly converted.</value>
- </data>
- <data name="Arg_RegSetStrArrNull" xml:space="preserve">
- <value>RegistryKey.SetValue does not allow a String[] that contains a null String reference.</value>
- </data>
<data name="Arg_RegSubKeyValueAbsent" xml:space="preserve">
<value>No value exists with that name.</value>
</data>
<data name="Arg_RegValStrLenBug" xml:space="preserve">
<value>Registry value names should not be greater than 16,383 characters.</value>
</data>
- <data name="Arg_RemoveArgNotFound" xml:space="preserve">
- <value>Cannot remove the specified item because it was not found in the specified Collection.</value>
- </data>
<data name="Arg_ResMgrNotResSet" xml:space="preserve">
<value>Type parameter must refer to a subclass of ResourceSet.</value>
</data>
@@ -3097,9 +3076,6 @@
<data name="ObjectDisposed_ReaderClosed" xml:space="preserve">
<value>Cannot read from a closed TextReader.</value>
</data>
- <data name="ObjectDisposed_RegKeyClosed" xml:space="preserve">
- <value>Cannot access a closed registry key.</value>
- </data>
<data name="ObjectDisposed_ResourceSet" xml:space="preserve">
<value>Cannot access a closed resource set.</value>
</data>
@@ -3562,9 +3538,6 @@
<data name="UnauthorizedAccess_RegistryKeyGeneric_Key" xml:space="preserve">
<value>Access to the registry key '{0}' is denied.</value>
</data>
- <data name="UnauthorizedAccess_RegistryNoWrite" xml:space="preserve">
- <value>Cannot write to the registry key.</value>
- </data>
<data name="UnauthorizedAccess_SystemDomain" xml:space="preserve">
<value>Cannot execute an assembly in the system domain.</value>
</data>
diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
index f18e763f40..a6abde38b8 100644
--- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -468,7 +468,6 @@
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\Microsoft\Win32\UnsafeNativeMethods.cs" />
<Compile Include="$(BclSourcesRoot)\Microsoft\Win32\Win32Native.cs" />
- <Compile Condition="'$(FeatureWin32Registry)' == 'true'" Include="$(BclSourcesRoot)\Microsoft\Win32\RegistryKey.cs" />
<Compile Condition="'$(FeatureClassicCominterop)' == 'true'" Include="$(BclSourcesRoot)\Microsoft\Win32\OAVariantLib.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/src/System.Private.CoreLib/shared/Internal/Win32/RegistryKey.cs b/src/System.Private.CoreLib/shared/Internal/Win32/RegistryKey.cs
new file mode 100644
index 0000000000..a98eef902b
--- /dev/null
+++ b/src/System.Private.CoreLib/shared/Internal/Win32/RegistryKey.cs
@@ -0,0 +1,485 @@
+// 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 file in the project root for more information.
+
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Security;
+
+using Internal.Win32.SafeHandles;
+
+//
+// A minimal version of RegistryKey that supports just what CoreLib needs.
+//
+// Internal.Win32 namespace avoids confusion with the public standalone Microsoft.Win32.Registry implementation
+// that lives in corefx.
+//
+namespace Internal.Win32
+{
+ internal sealed class RegistryKey : IDisposable
+ {
+ // MSDN defines the following limits for registry key names & values:
+ // Key Name: 255 characters
+ // Value name: 16,383 Unicode characters
+ // Value: either 1 MB or current available memory, depending on registry format.
+ private const int MaxKeyLength = 255;
+ private const int MaxValueLength = 16383;
+
+ private SafeRegistryHandle _hkey = null;
+
+ private RegistryKey(SafeRegistryHandle hkey)
+ {
+ _hkey = hkey;
+ }
+
+ void IDisposable.Dispose()
+ {
+ if (_hkey != null)
+ {
+ _hkey.Dispose();
+ }
+ }
+
+ public void DeleteValue(string name, bool throwOnMissingValue)
+ {
+ int errorCode = Interop.Advapi32.RegDeleteValue(_hkey, name);
+
+ //
+ // From windows 2003 server, if the name is too long we will get error code ERROR_FILENAME_EXCED_RANGE
+ // This still means the name doesn't exist. We need to be consistent with previous OS.
+ //
+ if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND ||
+ errorCode == Interop.Errors.ERROR_FILENAME_EXCED_RANGE)
+ {
+ if (throwOnMissingValue)
+ {
+ throw new ArgumentException(SR.Arg_RegSubKeyValueAbsent);
+ }
+ else
+ {
+ // Otherwise, reset and just return giving no indication to the user.
+ // (For compatibility)
+ errorCode = 0;
+ }
+ }
+ // We really should throw an exception here if errorCode was bad,
+ // but we can't for compatibility reasons.
+ Debug.Assert(errorCode == 0, "RegDeleteValue failed. Here's your error code: " + errorCode);
+ }
+
+ internal static RegistryKey OpenBaseKey(IntPtr hKey)
+ {
+ return new RegistryKey(new SafeRegistryHandle(hKey, false));
+ }
+
+ public RegistryKey OpenSubKey(string name)
+ {
+ return OpenSubKey(name, false);
+ }
+
+ public RegistryKey OpenSubKey(string name, bool writable)
+ {
+ // Make sure that the name does not contain double slahes
+ Debug.Assert(name.IndexOf("\\\\") == -1);
+
+ int ret = Interop.Advapi32.RegOpenKeyEx(_hkey,
+ name,
+ 0,
+ writable ?
+ Interop.Advapi32.RegistryOperations.KEY_READ | Interop.Advapi32.RegistryOperations.KEY_WRITE :
+ Interop.Advapi32.RegistryOperations.KEY_READ,
+ out SafeRegistryHandle result);
+
+ if (ret == 0 && !result.IsInvalid)
+ {
+ return new RegistryKey(result);
+ }
+
+ // Return null if we didn't find the key.
+ if (ret == Interop.Errors.ERROR_ACCESS_DENIED || ret == Interop.Errors.ERROR_BAD_IMPERSONATION_LEVEL)
+ {
+ // We need to throw SecurityException here for compatibility reasons,
+ // although UnauthorizedAccessException will make more sense.
+ throw new SecurityException(SR.Security_RegistryPermission);
+ }
+
+ return null;
+ }
+
+ public string[] GetSubKeyNames()
+ {
+ var names = new List<string>();
+ char[] name = ArrayPool<char>.Shared.Rent(MaxKeyLength + 1);
+
+ try
+ {
+ int result;
+ int nameLength = name.Length;
+
+ while ((result = Interop.Advapi32.RegEnumKeyEx(
+ _hkey,
+ names.Count,
+ name,
+ ref nameLength,
+ null,
+ null,
+ null,
+ null)) != Interop.Errors.ERROR_NO_MORE_ITEMS)
+ {
+ switch (result)
+ {
+ case Interop.Errors.ERROR_SUCCESS:
+ names.Add(new string(name, 0, nameLength));
+ nameLength = name.Length;
+ break;
+ default:
+ // Throw the error
+ Win32Error(result, null);
+ break;
+ }
+ }
+ }
+ finally
+ {
+ ArrayPool<char>.Shared.Return(name);
+ }
+
+ return names.ToArray();
+ }
+
+ public unsafe string[] GetValueNames()
+ {
+ var names = new List<string>();
+
+ // Names in the registry aren't usually very long, although they can go to as large
+ // as 16383 characters (MaxValueLength).
+ //
+ // Every call to RegEnumValue will allocate another buffer to get the data from
+ // NtEnumerateValueKey before copying it back out to our passed in buffer. This can
+ // add up quickly- we'll try to keep the memory pressure low and grow the buffer
+ // only if needed.
+
+ char[] name = ArrayPool<char>.Shared.Rent(100);
+
+ try
+ {
+ int result;
+ int nameLength = name.Length;
+
+ while ((result = Interop.Advapi32.RegEnumValue(
+ _hkey,
+ names.Count,
+ name,
+ ref nameLength,
+ IntPtr.Zero,
+ null,
+ null,
+ null)) != Interop.Errors.ERROR_NO_MORE_ITEMS)
+ {
+ switch (result)
+ {
+ // The size is only ever reported back correctly in the case
+ // of ERROR_SUCCESS. It will almost always be changed, however.
+ case Interop.Errors.ERROR_SUCCESS:
+ names.Add(new string(name, 0, nameLength));
+ break;
+ case Interop.Errors.ERROR_MORE_DATA:
+ {
+ char[] oldName = name;
+ int oldLength = oldName.Length;
+ name = null;
+ ArrayPool<char>.Shared.Return(oldName);
+ name = ArrayPool<char>.Shared.Rent(checked(oldLength * 2));
+ }
+ break;
+ default:
+ // Throw the error
+ Win32Error(result, null);
+ break;
+ }
+
+ // Always set the name length back to the buffer size
+ nameLength = name.Length;
+ }
+ }
+ finally
+ {
+ if (name != null)
+ ArrayPool<char>.Shared.Return(name);
+ }
+
+ return names.ToArray();
+ }
+
+ public object GetValue(string name)
+ {
+ return GetValue(name, null);
+ }
+
+ public object GetValue(string name, object defaultValue)
+ {
+ object data = defaultValue;
+ int type = 0;
+ int datasize = 0;
+
+ int ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, (byte[])null, ref datasize);
+
+ if (ret != 0)
+ {
+ // For stuff like ERROR_FILE_NOT_FOUND, we want to return null (data).
+ // Some OS's returned ERROR_MORE_DATA even in success cases, so we
+ // want to continue on through the function.
+ if (ret != Interop.Errors.ERROR_MORE_DATA)
+ return data;
+ }
+
+ if (datasize < 0)
+ {
+ // unexpected code path
+ Debug.Fail("[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
+ datasize = 0;
+ }
+
+
+ switch (type)
+ {
+ case Interop.Advapi32.RegistryValues.REG_NONE:
+ case Interop.Advapi32.RegistryValues.REG_DWORD_BIG_ENDIAN:
+ case Interop.Advapi32.RegistryValues.REG_BINARY:
+ {
+ byte[] blob = new byte[datasize];
+ ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
+ data = blob;
+ }
+ break;
+ case Interop.Advapi32.RegistryValues.REG_QWORD:
+ { // also REG_QWORD_LITTLE_ENDIAN
+ if (datasize > 8)
+ {
+ // prevent an AV in the edge case that datasize is larger than sizeof(long)
+ goto case Interop.Advapi32.RegistryValues.REG_BINARY;
+ }
+ long blob = 0;
+ Debug.Assert(datasize == 8, "datasize==8");
+ // Here, datasize must be 8 when calling this
+ ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, ref blob, ref datasize);
+
+ data = blob;
+ }
+ break;
+ case Interop.Advapi32.RegistryValues.REG_DWORD:
+ { // also REG_DWORD_LITTLE_ENDIAN
+ if (datasize > 4)
+ {
+ // prevent an AV in the edge case that datasize is larger than sizeof(int)
+ goto case Interop.Advapi32.RegistryValues.REG_QWORD;
+ }
+ int blob = 0;
+ Debug.Assert(datasize == 4, "datasize==4");
+ // Here, datasize must be four when calling this
+ ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, ref blob, ref datasize);
+
+ data = blob;
+ }
+ break;
+
+ case Interop.Advapi32.RegistryValues.REG_SZ:
+ {
+ if (datasize % 2 == 1)
+ {
+ // handle the case where the registry contains an odd-byte length (corrupt data?)
+ try
+ {
+ datasize = checked(datasize + 1);
+ }
+ catch (OverflowException e)
+ {
+ throw new IOException(SR.Arg_RegGetOverflowBug, e);
+ }
+ }
+ char[] blob = new char[datasize / 2];
+
+ ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
+ if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
+ {
+ data = new string(blob, 0, blob.Length - 1);
+ }
+ else
+ {
+ // in the very unlikely case the data is missing null termination,
+ // pass in the whole char[] to prevent truncating a character
+ data = new string(blob);
+ }
+ }
+ break;
+
+ case Interop.Advapi32.RegistryValues.REG_EXPAND_SZ:
+ {
+ if (datasize % 2 == 1)
+ {
+ // handle the case where the registry contains an odd-byte length (corrupt data?)
+ try
+ {
+ datasize = checked(datasize + 1);
+ }
+ catch (OverflowException e)
+ {
+ throw new IOException(SR.Arg_RegGetOverflowBug, e);
+ }
+ }
+ char[] blob = new char[datasize / 2];
+
+ ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
+
+ if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
+ {
+ data = new string(blob, 0, blob.Length - 1);
+ }
+ else
+ {
+ // in the very unlikely case the data is missing null termination,
+ // pass in the whole char[] to prevent truncating a character
+ data = new string(blob);
+ }
+
+ data = Environment.ExpandEnvironmentVariables((string)data);
+ }
+ break;
+ case Interop.Advapi32.RegistryValues.REG_MULTI_SZ:
+ {
+ if (datasize % 2 == 1)
+ {
+ // handle the case where the registry contains an odd-byte length (corrupt data?)
+ try
+ {
+ datasize = checked(datasize + 1);
+ }
+ catch (OverflowException e)
+ {
+ throw new IOException(SR.Arg_RegGetOverflowBug, e);
+ }
+ }
+ char[] blob = new char[datasize / 2];
+
+ ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
+
+ // make sure the string is null terminated before processing the data
+ if (blob.Length > 0 && blob[blob.Length - 1] != (char)0)
+ {
+ Array.Resize(ref blob, blob.Length + 1);
+ }
+
+ string[] strings = Array.Empty<string>();
+ int stringsCount = 0;
+
+ int cur = 0;
+ int len = blob.Length;
+
+ while (ret == 0 && cur < len)
+ {
+ int nextNull = cur;
+ while (nextNull < len && blob[nextNull] != (char)0)
+ {
+ nextNull++;
+ }
+
+ string toAdd = null;
+ if (nextNull < len)
+ {
+ Debug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
+ if (nextNull - cur > 0)
+ {
+ toAdd = new string(blob, cur, nextNull - cur);
+ }
+ else
+ {
+ // we found an empty string. But if we're at the end of the data,
+ // it's just the extra null terminator.
+ if (nextNull != len - 1)
+ {
+ toAdd = string.Empty;
+ }
+ }
+ }
+ else
+ {
+ toAdd = new string(blob, cur, len - cur);
+ }
+ cur = nextNull + 1;
+
+ if (toAdd != null)
+ {
+ if (strings.Length == stringsCount)
+ {
+ Array.Resize(ref strings, stringsCount > 0 ? stringsCount * 2 : 4);
+ }
+ strings[stringsCount++] = toAdd;
+ }
+ }
+
+ Array.Resize(ref strings, stringsCount);
+ data = strings;
+ }
+ break;
+ case Interop.Advapi32.RegistryValues.REG_LINK:
+ default:
+ break;
+ }
+
+ return data;
+ }
+
+ // The actual api is SetValue(string name, object value) but we only need to set Strings
+ // so this is a cut-down version that supports on that.
+ internal void SetValue(string name, string value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (name != null && name.Length > MaxValueLength)
+ throw new ArgumentException(SR.Arg_RegValStrLenBug, nameof(name));
+
+ int ret = Interop.Advapi32.RegSetValueEx(_hkey,
+ name,
+ 0,
+ Interop.Advapi32.RegistryValues.REG_SZ,
+ value,
+ checked(value.Length * 2 + 2));
+
+ if (ret != 0)
+ {
+ Win32Error(ret, null);
+ }
+ }
+
+ internal void Win32Error(int errorCode, string str)
+ {
+ switch (errorCode)
+ {
+ case Interop.Errors.ERROR_ACCESS_DENIED:
+ if (str != null)
+ throw new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_RegistryKeyGeneric_Key, str));
+ else
+ throw new UnauthorizedAccessException();
+
+ case Interop.Errors.ERROR_FILE_NOT_FOUND:
+ throw new IOException(SR.Arg_RegKeyNotFound, errorCode);
+
+ default:
+ throw new IOException(Interop.Kernel32.GetMessage(errorCode), errorCode);
+ }
+ }
+ }
+
+ internal static class Registry
+ {
+ /// <summary>Current User Key. This key should be used as the root for all user specific settings.</summary>
+ public static readonly RegistryKey CurrentUser = RegistryKey.OpenBaseKey(unchecked((IntPtr)(int)0x80000001));
+
+ /// <summary>Local Machine key. This key should be used as the root for all machine specific settings.</summary>
+ public static readonly RegistryKey LocalMachine = RegistryKey.OpenBaseKey(unchecked((IntPtr)(int)0x80000002));
+ }
+}
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs
index e5219064bc..b6c6d9809c 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs
index 4429515cdd..c949cc15ff 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs
index b8044bc79d..378666908e 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs
index bedf282773..499329d7d3 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
using System.Text;
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumValue.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumValue.cs
index e02ba98fef..28d24e208a 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumValue.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegEnumValue.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegFlushKey.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegFlushKey.cs
index 8f72798f87..fa56f48399 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegFlushKey.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegFlushKey.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System.Runtime.InteropServices;
internal partial class Interop
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs
index 86b6bcae29..d186d98043 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryInfoKey.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryInfoKey.cs
index 2df2092885..a0e5f27b47 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryInfoKey.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryInfoKey.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
using System.Text;
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs
index c6a8798179..2ab3ba019e 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs
@@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
using System.Text;
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs
index d46f84809a..7fb479ee09 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs
@@ -2,8 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32;
+#if REGISTRY_ASSEMBLY
using Microsoft.Win32.SafeHandles;
+#else
+using Internal.Win32.SafeHandles;
+#endif
using System;
using System.Runtime.InteropServices;
@@ -16,7 +19,7 @@ internal partial class Interop
SafeRegistryHandle hKey,
string lpValueName,
int Reserved,
- RegistryValueKind dwType,
+ int dwType,
byte[] lpData,
int cbData);
@@ -25,7 +28,7 @@ internal partial class Interop
SafeRegistryHandle hKey,
string lpValueName,
int Reserved,
- RegistryValueKind dwType,
+ int dwType,
char[] lpData,
int cbData);
@@ -34,7 +37,7 @@ internal partial class Interop
SafeRegistryHandle hKey,
string lpValueName,
int Reserved,
- RegistryValueKind dwType,
+ int dwType,
ref int lpData,
int cbData);
@@ -43,7 +46,7 @@ internal partial class Interop
SafeRegistryHandle hKey,
string lpValueName,
int Reserved,
- RegistryValueKind dwType,
+ int dwType,
ref long lpData,
int cbData);
@@ -52,7 +55,7 @@ internal partial class Interop
SafeRegistryHandle hKey,
string lpValueName,
int Reserved,
- RegistryValueKind dwType,
+ int dwType,
string lpData,
int cbData);
}
diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/Registry.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/Registry.cs
deleted file mode 100644
index d9b1d9dd08..0000000000
--- a/src/System.Private.CoreLib/shared/Microsoft/Win32/Registry.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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 file in the project root for more information.
-
-using System;
-using System.Diagnostics;
-
-namespace Microsoft.Win32
-{
- /// <summary>Registry encapsulation. Contains members representing all top level system keys.</summary>
-#if REGISTRY_ASSEMBLY
- public
-#else
- internal
-#endif
- static class Registry
- {
- /// <summary>Current User Key. This key should be used as the root for all user specific settings.</summary>
- public static readonly RegistryKey CurrentUser = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
-
- /// <summary>Local Machine key. This key should be used as the root for all machine specific settings.</summary>
- public static readonly RegistryKey LocalMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default);
-
-#if REGISTRY_ASSEMBLY
- /// <summary>Classes Root Key. This is the root key of class information.</summary>
- public static readonly RegistryKey ClassesRoot = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Default);
-
- /// <summary>Users Root Key. This is the root of users.</summary>
- public static readonly RegistryKey Users = RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Default);
-
- /// <summary>Performance Root Key. This is where dynamic performance data is stored on NT.</summary>
- public static readonly RegistryKey PerformanceData = RegistryKey.OpenBaseKey(RegistryHive.PerformanceData, RegistryView.Default);
-
- /// <summary>Current Config Root Key. This is where current configuration information is stored.</summary>
- public static readonly RegistryKey CurrentConfig = RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, RegistryView.Default);
-
- /// <summary>
- /// Parse a keyName and returns the basekey for it.
- /// It will also store the subkey name in the out parameter.
- /// If the keyName is not valid, we will throw ArgumentException.
- /// The return value shouldn't be null.
- /// </summary>
- private static RegistryKey GetBaseKeyFromKeyName(string keyName, out string subKeyName)
- {
- if (keyName == null)
- {
- throw new ArgumentNullException(nameof(keyName));
- }
-
- int i = keyName.IndexOf('\\');
- int length = i != -1 ? i : keyName.Length;
-
- // Determine the potential base key from the length.
- RegistryKey baseKey = null;
- switch (length)
- {
- case 10: baseKey = Users; break; // HKEY_USERS
- case 17: baseKey = char.ToUpperInvariant(keyName[6]) == 'L' ? ClassesRoot : CurrentUser; break; // HKEY_C[L]ASSES_ROOT, otherwise HKEY_CURRENT_USER
- case 18: baseKey = LocalMachine; break; // HKEY_LOCAL_MACHINE
- case 19: baseKey = CurrentConfig; break; // HKEY_CURRENT_CONFIG
- case 21: baseKey = PerformanceData; break; // HKEY_PERFORMANCE_DATA
- }
-
- // If a potential base key was found, see if keyName actually starts with the potential base key's name.
- if (baseKey != null && keyName.StartsWith(baseKey.Name, StringComparison.OrdinalIgnoreCase))
- {
- subKeyName = (i == -1 || i == keyName.Length) ?
- string.Empty :
- keyName.Substring(i + 1, keyName.Length - i - 1);
-
- return baseKey;
- }
-
- throw new ArgumentException(SR.Format(SR.Arg_RegInvalidKeyName, nameof(keyName)), nameof(keyName));
- }
-
- public static object GetValue(string keyName, string valueName, object defaultValue)
- {
- string subKeyName;
- RegistryKey basekey = GetBaseKeyFromKeyName(keyName, out subKeyName);
-
- using (RegistryKey key = basekey.OpenSubKey(subKeyName))
- {
- return key?.GetValue(valueName, defaultValue);
- }
- }
-
- public static void SetValue(string keyName, string valueName, object value)
- {
- SetValue(keyName, valueName, value, RegistryValueKind.Unknown);
- }
-
- public static void SetValue(string keyName, string valueName, object value, RegistryValueKind valueKind)
- {
- string subKeyName;
- RegistryKey basekey = GetBaseKeyFromKeyName(keyName, out subKeyName);
-
- using (RegistryKey key = basekey.CreateSubKey(subKeyName))
- {
- Debug.Assert(key != null, "An exception should be thrown if failed!");
- key.SetValue(valueName, value, valueKind);
- }
- }
-#endif
- }
-}
diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryHive.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryHive.cs
deleted file mode 100644
index 0f1e9541c8..0000000000
--- a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryHive.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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 file in the project root for more information.
-
-namespace Microsoft.Win32
-{
- /**
- * Registry hive values. Useful only for GetRemoteBaseKey
- */
-#if REGISTRY_ASSEMBLY
- public
-#else
- internal
-#endif
- enum RegistryHive
- {
- ClassesRoot = unchecked((int)0x80000000),
- CurrentUser = unchecked((int)0x80000001),
- LocalMachine = unchecked((int)0x80000002),
- Users = unchecked((int)0x80000003),
- PerformanceData = unchecked((int)0x80000004),
- CurrentConfig = unchecked((int)0x80000005),
- }
-} \ No newline at end of file
diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryOptions.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryOptions.cs
deleted file mode 100644
index 201a6df0ec..0000000000
--- a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryOptions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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 file in the project root for more information.
-
-using System;
-
-namespace Microsoft.Win32
-{
- [Flags]
-#if REGISTRY_ASSEMBLY
- public
-#else
- internal
-#endif
- enum RegistryOptions
- {
- None = Interop.Advapi32.RegistryOptions.REG_OPTION_NON_VOLATILE, // 0x0000
- Volatile = Interop.Advapi32.RegistryOptions.REG_OPTION_VOLATILE, // 0x0001
- };
-}
diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueKind.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueKind.cs
deleted file mode 100644
index bc6efcc06f..0000000000
--- a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueKind.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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 file in the project root for more information.
-
-namespace Microsoft.Win32
-{
-#if REGISTRY_ASSEMBLY
- public
-#else
- internal
-#endif
- enum RegistryValueKind
- {
- String = Interop.Advapi32.RegistryValues.REG_SZ,
- ExpandString = Interop.Advapi32.RegistryValues.REG_EXPAND_SZ,
- Binary = Interop.Advapi32.RegistryValues.REG_BINARY,
- DWord = Interop.Advapi32.RegistryValues.REG_DWORD,
- MultiString = Interop.Advapi32.RegistryValues.REG_MULTI_SZ,
- QWord = Interop.Advapi32.RegistryValues.REG_QWORD,
- Unknown = 0, // REG_NONE is defined as zero but BCL
- None = unchecked((int)0xFFFFFFFF), // mistakenly overrode this value.
- } // Now instead of using Interop.Kernel32.RegistryValues.REG_NONE we use "-1".
-}
diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueOptions.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueOptions.cs
deleted file mode 100644
index 7d9b6c403b..0000000000
--- a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueOptions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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 file in the project root for more information.
-
-using System;
-
-namespace Microsoft.Win32
-{
- [Flags]
-#if REGISTRY_ASSEMBLY
- public
-#else
- internal
-#endif
- enum RegistryValueOptions
- {
- None = 0,
- DoNotExpandEnvironmentNames = 1
- }
-}
diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryView.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryView.cs
deleted file mode 100644
index 0d6b3038e8..0000000000
--- a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryView.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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 file in the project root for more information.
-
-using System;
-
-namespace Microsoft.Win32
-{
-#if REGISTRY_ASSEMBLY
- public
-#else
- internal
-#endif
- enum RegistryView
- {
- Default = 0, // 0x0000 operate on the default registry view
- Registry64 = Interop.Advapi32.RegistryView.KEY_WOW64_64KEY, // 0x0100 operate on the 64-bit registry view
- Registry32 = Interop.Advapi32.RegistryView.KEY_WOW64_32KEY, // 0x0200 operate on the 32-bit registry view
- };
-}
diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.Windows.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.Windows.cs
index 9b668047a9..249f5e9f7c 100644
--- a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.Windows.cs
+++ b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.Windows.cs
@@ -2,9 +2,14 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
+#if REGISTRY_ASSEMBLY
namespace Microsoft.Win32.SafeHandles
+#else
+namespace Internal.Win32.SafeHandles
+#endif
{
#if REGISTRY_ASSEMBLY
public
diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.cs
index ae35b03d54..37e350031b 100644
--- a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.cs
+++ b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeRegistryHandle.cs
@@ -2,9 +2,14 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using Microsoft.Win32.SafeHandles;
using System;
+#if REGISTRY_ASSEMBLY
namespace Microsoft.Win32.SafeHandles
+#else
+namespace Internal.Win32.SafeHandles
+#endif
{
#if REGISTRY_ASSEMBLY
public
diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
index 771ab3855f..af7493c2cc 100644
--- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
@@ -807,6 +807,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Windows.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetsWindows) and '$(EnableWinRT)' != 'true'">
+ <Compile Include="$(MSBuildThisFileDirectory)Internal\Win32\RegistryKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.RegCloseKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.RegCreateKeyEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.RegDeleteKeyEx.cs" />
@@ -819,15 +820,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.RegQueryInfoKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.RegQueryValueEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.RegSetValueEx.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\Registry.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryHive.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryOptions.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryValueKind.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryValueOptions.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeRegistryHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeRegistryHandle.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Security\AccessControl\RegistryRights.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CreateFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FreeLibrary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs" />
diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs
index 9e52ba2adc..c0838196d5 100644
--- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs
+++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs
@@ -10,7 +10,10 @@ using System.Runtime.InteropServices;
using System.Security;
#if !CORECLR && !ES_BUILD_PN
using System.Security.Permissions;
-#endif // !CORECLR && !ES_BUILD_PN
+#endif
+#if CORECLR && PLATFORM_WINDOWS
+using Internal.Win32;
+#endif
using System.Threading;
using System;
@@ -512,7 +515,7 @@ namespace System.Diagnostics.Tracing
else
regKey = @"Software" + regKey;
- using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(regKey))
+ using (var key = Registry.LocalMachine.OpenSubKey(regKey))
{
if (key != null)
{
@@ -595,7 +598,7 @@ namespace System.Diagnostics.Tracing
#if !CORECLR
(new RegistryPermission(RegistryPermissionAccess.Read, regKey)).Assert();
#endif
- using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(regKey))
+ using (var key = Registry.LocalMachine.OpenSubKey(regKey))
{
data = key?.GetValue(valueName, null) as byte[];
if (data != null)
diff --git a/src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs b/src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs
index 8c23e4651d..671a882412 100644
--- a/src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs
+++ b/src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32;
+using Internal.Win32;
namespace System.Globalization
{
@@ -47,7 +47,7 @@ namespace System.Globalization
return 0;
}
- object value = key.GetValue(HijriAdvanceRegKeyEntry, null, RegistryValueOptions.DoNotExpandEnvironmentNames);
+ object value = key.GetValue(HijriAdvanceRegKeyEntry);
if (value == null)
{
return 0;
diff --git a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs
index 8657d31b66..1a8ba7c44b 100644
--- a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs
+++ b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs
@@ -4,7 +4,7 @@
using System.Diagnostics;
-using Microsoft.Win32;
+using Internal.Win32;
namespace System.Globalization
{
diff --git a/src/System.Private.CoreLib/shared/System/Security/AccessControl/RegistryRights.cs b/src/System.Private.CoreLib/shared/System/Security/AccessControl/RegistryRights.cs
deleted file mode 100644
index 729e2f6b58..0000000000
--- a/src/System.Private.CoreLib/shared/System/Security/AccessControl/RegistryRights.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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 file in the project root for more information.
-
-using Microsoft.Win32;
-
-namespace System.Security.AccessControl
-{
- // We derived this enum from the definitions of KEY_READ and such from
- // winnt.h and from MSDN, plus some experimental validation with regedit.
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/registry_key_security_and_access_rights.asp
- [Flags]
-#if REGISTRY_ASSEMBLY
- public
-#else
- internal
-#endif
- enum RegistryRights
- {
- // No None field - An ACE with the value 0 cannot grant nor deny.
- QueryValues = Interop.Advapi32.RegistryOperations.KEY_QUERY_VALUE, // 0x0001 query the values of a registry key
- SetValue = Interop.Advapi32.RegistryOperations.KEY_SET_VALUE, // 0x0002 create, delete, or set a registry value
- CreateSubKey = Interop.Advapi32.RegistryOperations.KEY_CREATE_SUB_KEY, // 0x0004 required to create a subkey of a specific key
- EnumerateSubKeys = Interop.Advapi32.RegistryOperations.KEY_ENUMERATE_SUB_KEYS, // 0x0008 required to enumerate sub keys of a key
- Notify = Interop.Advapi32.RegistryOperations.KEY_NOTIFY, // 0x0010 needed to request change notifications
- CreateLink = Interop.Advapi32.RegistryOperations.KEY_CREATE_LINK, // 0x0020 reserved for system use
- ///
- /// The Windows Kernel team agrees that it was a bad design to expose the WOW64_n options as permissions.
- /// in the .NET Framework these options are exposed via the RegistryView enum
- ///
- /// Reg64 = Interop.Advapi32.RegistryOptions.KEY_WOW64_64KEY, // 0x0100 operate on the 64-bit registry view
- /// Reg32 = Interop.Advapi32.RegistryOptions.KEY_WOW64_32KEY, // 0x0200 operate on the 32-bit registry view
- ExecuteKey = ReadKey,
- ReadKey = Interop.Advapi32.RegistryOperations.STANDARD_RIGHTS_READ | QueryValues | EnumerateSubKeys | Notify,
- WriteKey = Interop.Advapi32.RegistryOperations.STANDARD_RIGHTS_WRITE | SetValue | CreateSubKey,
- Delete = 0x10000,
- ReadPermissions = 0x20000,
- ChangePermissions = 0x40000,
- TakeOwnership = 0x80000,
- FullControl = 0xF003F | Interop.Advapi32.RegistryOperations.STANDARD_RIGHTS_READ | Interop.Advapi32.RegistryOperations.STANDARD_RIGHTS_WRITE
- }
-}
diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs
index 03e7926d65..d81b9f01fd 100644
--- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs
+++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs
@@ -10,9 +10,9 @@ using System.Security;
using System.Text;
using System.Threading;
-using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
+using Internal.Win32;
using Internal.Runtime.CompilerServices;
using REG_TZI_FORMAT = Interop.Kernel32.REG_TZI_FORMAT;
diff --git a/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.cs b/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.cs
deleted file mode 100644
index 3176adab9b..0000000000
--- a/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.cs
+++ /dev/null
@@ -1,1137 +0,0 @@
-// 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 file in the project root for more information.
-
-/*
- Note on transaction support:
- Eventually we will want to add support for NT's transactions to our
- RegistryKey API's. When we do this, here's
- the list of API's we need to make transaction-aware:
-
- RegCreateKeyEx
- RegDeleteKey
- RegDeleteValue
- RegEnumKeyEx
- RegEnumValue
- RegOpenKeyEx
- RegQueryInfoKey
- RegQueryValueEx
- RegSetValueEx
-
- We can ignore RegConnectRegistry (remote registry access doesn't yet have
- transaction support) and RegFlushKey. RegCloseKey doesn't require any
- additional work.
- */
-
-/*
- Note on ACL support:
- The key thing to note about ACL's is you set them on a kernel object like a
- registry key, then the ACL only gets checked when you construct handles to
- them. So if you set an ACL to deny read access to yourself, you'll still be
- able to read with that handle, but not with new handles.
-
- Another peculiarity is a Terminal Server app compatibility workaround. The OS
- will second guess your attempt to open a handle sometimes. If a certain
- combination of Terminal Server app compat registry keys are set, then the
- OS will try to reopen your handle with lesser permissions if you couldn't
- open it in the specified mode. So on some machines, we will see handles that
- may not be able to read or write to a registry key. It's very strange. But
- the real test of these handles is attempting to read or set a value in an
- affected registry key.
-
- For reference, at least two registry keys must be set to particular values
- for this behavior:
- HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\RegistryExtensionFlags, the least significant bit must be 1.
- HKLM\SYSTEM\CurrentControlSet\Control\TerminalServer\TSAppCompat must be 1
- There might possibly be an interaction with yet a third registry key as well.
-*/
-
-using Microsoft.Win32.SafeHandles;
-using System;
-using System.Buffers;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Security;
-using System.Text;
-
-namespace Microsoft.Win32
-{
- /// <summary>Registry encapsulation. To get an instance of a RegistryKey use the Registry class's static members then call OpenSubKey.</summary>
-#if REGISTRY_ASSEMBLY
- public
-#else
- internal
-#endif
- sealed class RegistryKey : MarshalByRefObject, IDisposable
- {
- // We could use const here, if C# supported ELEMENT_TYPE_I fully.
- internal static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000));
- internal static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));
- internal static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
- internal static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003));
- internal static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004));
- internal static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005));
-
- /// <summary>Names of keys. This array must be in the same order as the HKEY values listed above.</summary>
- private static readonly string[] s_hkeyNames = new string[]
- {
- "HKEY_CLASSES_ROOT",
- "HKEY_CURRENT_USER",
- "HKEY_LOCAL_MACHINE",
- "HKEY_USERS",
- "HKEY_PERFORMANCE_DATA",
- "HKEY_CURRENT_CONFIG"
- };
-
- // MSDN defines the following limits for registry key names & values:
- // Key Name: 255 characters
- // Value name: 16,383 Unicode characters
- // Value: either 1 MB or current available memory, depending on registry format.
- private const int MaxKeyLength = 255;
- private const int MaxValueLength = 16383;
-
- private volatile SafeRegistryHandle _hkey = null;
- private volatile string _keyName;
- private volatile bool _remoteKey = false;
- private volatile StateFlags _state;
- private volatile RegistryKeyPermissionCheck checkMode;
- private volatile RegistryView _regView = RegistryView.Default;
-
- /// <summary>
- /// Creates a RegistryKey.
- /// This key is bound to hkey, if writable is <b>false</b> then no write operations
- /// will be allowed. If systemkey is set then the hkey won't be released
- /// when the object is GC'ed.
- /// The remoteKey flag when set to true indicates that we are dealing with registry entries
- /// on a remote machine and requires the program making these calls to have full trust.
- /// </summary>
- private RegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey, bool remoteKey, bool isPerfData, RegistryView view)
- {
- _hkey = hkey;
- _keyName = "";
- _remoteKey = remoteKey;
- _regView = view;
-
- if (systemkey)
- {
- _state |= StateFlags.SystemKey;
- }
- if (writable)
- {
- _state |= StateFlags.WriteAccess;
- }
- if (isPerfData)
- {
- _state |= StateFlags.PerfData;
- }
- ValidateKeyView(view);
- }
-
- /// <summary>Retrieves a string representation of this key.</summary>
- /// <returns>A string representing the key.</returns>
- public override string ToString()
- {
- EnsureNotDisposed();
- return _keyName;
- }
-
- public string Name
- {
- get
- {
- EnsureNotDisposed();
- return _keyName;
- }
- }
-
- private static void FixupPath(StringBuilder path)
- {
- Debug.Assert(path != null);
- int length = path.Length;
- bool fixup = false;
- char markerChar = (char)0xFFFF;
-
- int i = 1;
- while (i < length - 1)
- {
- if (path[i] == '\\')
- {
- i++;
- while (i < length)
- {
- if (path[i] == '\\')
- {
- path[i] = markerChar;
- i++;
- fixup = true;
- }
- else
- break;
- }
- }
- i++;
- }
-
- if (fixup)
- {
- i = 0;
- int j = 0;
- while (i < length)
- {
- if (path[i] == markerChar)
- {
- i++;
- continue;
- }
- path[j] = path[i];
- i++;
- j++;
- }
- path.Length += j - i;
- }
- }
-
- /// <summary>Retrieves the current state of the dirty property.</summary>
- /// <remarks>A key is marked as dirty if any operation has occurred that modifies the contents of the key.</remarks>
- /// <returns><b>true</b> if the key has been modified.</returns>
- private bool IsDirty() => (_state & StateFlags.Dirty) != 0;
-
- private bool IsSystemKey() => (_state & StateFlags.SystemKey) != 0;
-
- private bool IsWritable() => (_state & StateFlags.WriteAccess) != 0;
-
- private bool IsPerfDataKey() => (_state & StateFlags.PerfData) != 0;
-
- private void SetDirty() => _state |= StateFlags.Dirty;
-
- [Flags]
- private enum StateFlags
- {
- /// <summary>Dirty indicates that we have munged data that should be potentially written to disk.</summary>
- Dirty = 0x0001,
- /// <summary>SystemKey indicates that this is a "SYSTEMKEY" and shouldn't be "opened" or "closed".</summary>
- SystemKey = 0x0002,
- /// <summary>Access</summary>
- WriteAccess = 0x0004,
- /// <summary>Indicates if this key is for HKEY_PERFORMANCE_DATA</summary>
- PerfData = 0x0008
- }
-
- /**
- * Closes this key, flushes it to disk if the contents have been modified.
- */
- public void Close()
- {
- Dispose(true);
- }
-
- private void Dispose(bool disposing)
- {
- if (_hkey != null)
- {
- if (!IsSystemKey())
- {
- try
- {
- _hkey.Dispose();
- }
- catch (IOException)
- {
- // we don't really care if the handle is invalid at this point
- }
- finally
- {
- _hkey = null;
- }
- }
- else if (disposing && IsPerfDataKey())
- {
- // System keys should never be closed. However, we want to call RegCloseKey
- // on HKEY_PERFORMANCE_DATA when called from PerformanceCounter.CloseSharedResources
- // (i.e. when disposing is true) so that we release the PERFLIB cache and cause it
- // to be refreshed (by re-reading the registry) when accessed subsequently.
- // This is the only way we can see the just installed perf counter.
- // NOTE: since HKEY_PERFORMANCE_DATA is process wide, there is inherent race condition in closing
- // the key asynchronously. While Vista is smart enough to rebuild the PERFLIB resources
- // in this situation the down level OSes are not. We have a small window between
- // the dispose below and usage elsewhere (other threads). This is By Design.
- // This is less of an issue when OS > NT5 (i.e Vista & higher), we can close the perfkey
- // (to release & refresh PERFLIB resources) and the OS will rebuild PERFLIB as necessary.
- Interop.Advapi32.RegCloseKey(RegistryKey.HKEY_PERFORMANCE_DATA);
- }
- }
- }
-
- void IDisposable.Dispose()
- {
- Dispose(true);
- }
-
- public void DeleteValue(string name, bool throwOnMissingValue)
- {
- EnsureWriteable();
- int errorCode = Interop.Advapi32.RegDeleteValue(_hkey, name);
-
- //
- // From windows 2003 server, if the name is too long we will get error code ERROR_FILENAME_EXCED_RANGE
- // This still means the name doesn't exist. We need to be consistent with previous OS.
- //
- if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || errorCode == Interop.Errors.ERROR_FILENAME_EXCED_RANGE)
- {
- if (throwOnMissingValue)
- {
- throw new ArgumentException(SR.Arg_RegSubKeyValueAbsent);
- }
- // Otherwise, just return giving no indication to the user.
- // (For compatibility)
- }
- // We really should throw an exception here if errorCode was bad,
- // but we can't for compatibility reasons.
- Debug.Assert(errorCode == 0, "RegDeleteValue failed. Here's your error code: " + errorCode);
- }
-
- /**
- * Retrieves a new RegistryKey that represents the requested key. Valid
- * values are:
- *
- * HKEY_CLASSES_ROOT,
- * HKEY_CURRENT_USER,
- * HKEY_LOCAL_MACHINE,
- * HKEY_USERS,
- * HKEY_PERFORMANCE_DATA,
- * HKEY_CURRENT_CONFIG,
- * HKEY_DYN_DATA.
- *
- * @param hKey HKEY_* to open.
- *
- * @return the RegistryKey requested.
- */
- internal static RegistryKey OpenBaseKey(RegistryHive hKey)
- {
- return OpenBaseKey(hKey, RegistryView.Default);
- }
-
- internal static RegistryKey OpenBaseKey(RegistryHive hKeyHive, RegistryView view)
- {
- IntPtr hKey = (IntPtr)((int)hKeyHive);
- int index = ((int)hKey) & 0x0FFFFFFF;
- Debug.Assert(index >= 0 && index < s_hkeyNames.Length, "index is out of range!");
- Debug.Assert((((int)hKey) & 0xFFFFFFF0) == 0x80000000, "Invalid hkey value!");
-
- bool isPerf = hKey == HKEY_PERFORMANCE_DATA;
- // only mark the SafeHandle as ownsHandle if the key is HKEY_PERFORMANCE_DATA.
- SafeRegistryHandle srh = new SafeRegistryHandle(hKey, isPerf);
-
- RegistryKey key = new RegistryKey(srh, true, true, false, isPerf, view);
- key.checkMode = RegistryKeyPermissionCheck.Default;
- key._keyName = s_hkeyNames[index];
- return key;
- }
-
- /**
- * Retrieves a subkey. If readonly is <b>true</b>, then the subkey is opened with
- * read-only access.
- *
- * @param name Name or path of subkey to open.
- * @param readonly Set to <b>true</b> if you only need readonly access.
- *
- * @return the Subkey requested, or <b>null</b> if the operation failed.
- */
- public RegistryKey OpenSubKey(string name, bool writable)
- {
- ValidateKeyName(name);
- EnsureNotDisposed();
- name = FixupName(name); // Fixup multiple slashes to a single slash
-
- SafeRegistryHandle result = null;
- int ret = Interop.Advapi32.RegOpenKeyEx(_hkey,
- name,
- 0,
- GetRegistryKeyAccess(writable) | (int)_regView,
- out result);
-
- if (ret == 0 && !result.IsInvalid)
- {
- RegistryKey key = new RegistryKey(result, writable, false, _remoteKey, false, _regView);
- key.checkMode = GetSubKeyPermissonCheck(writable);
- key._keyName = _keyName + "\\" + name;
- return key;
- }
-
- // Return null if we didn't find the key.
- if (ret == Interop.Errors.ERROR_ACCESS_DENIED || ret == Interop.Errors.ERROR_BAD_IMPERSONATION_LEVEL)
- {
- // We need to throw SecurityException here for compatibility reasons,
- // although UnauthorizedAccessException will make more sense.
- throw new SecurityException(SR.Security_RegistryPermission);
- }
-
- return null;
- }
-
- /**
- * Returns a subkey with read only permissions.
- *
- * @param name Name or path of subkey to open.
- *
- * @return the Subkey requested, or <b>null</b> if the operation failed.
- */
- public RegistryKey OpenSubKey(string name)
- {
- return OpenSubKey(name, false);
- }
-
- /// <summary>
- /// Retrieves an array of strings containing all the subkey names.
- /// </summary>
- public string[] GetSubKeyNames()
- {
- EnsureNotDisposed();
-
- var names = new List<string>();
- char[] name = ArrayPool<char>.Shared.Rent(MaxKeyLength + 1);
-
- try
- {
- int result;
- int nameLength = name.Length;
-
- while ((result = Interop.Advapi32.RegEnumKeyEx(
- _hkey,
- names.Count,
- name,
- ref nameLength,
- null,
- null,
- null,
- null)) != Interop.Errors.ERROR_NO_MORE_ITEMS)
- {
- switch (result)
- {
- case Interop.Errors.ERROR_SUCCESS:
- names.Add(new string(name, 0, nameLength));
- nameLength = name.Length;
- break;
- default:
- // Throw the error
- Win32Error(result, null);
- break;
- }
- }
- }
- finally
- {
- ArrayPool<char>.Shared.Return(name);
- }
-
- return names.ToArray();
- }
-
- /// <summary>
- /// Retrieves an array of strings containing all the value names.
- /// </summary>
- public unsafe string[] GetValueNames()
- {
- EnsureNotDisposed();
- var names = new List<string>();
-
- // Names in the registry aren't usually very long, although they can go to as large
- // as 16383 characters (MaxValueLength).
- //
- // Every call to RegEnumValue will allocate another buffer to get the data from
- // NtEnumerateValueKey before copying it back out to our passed in buffer. This can
- // add up quickly- we'll try to keep the memory pressure low and grow the buffer
- // only if needed.
-
- char[] name = ArrayPool<char>.Shared.Rent(100);
-
- try
- {
- int result;
- int nameLength = name.Length;
-
- while ((result = Interop.Advapi32.RegEnumValue(
- _hkey,
- names.Count,
- name,
- ref nameLength,
- IntPtr.Zero,
- null,
- null,
- null)) != Interop.Errors.ERROR_NO_MORE_ITEMS)
- {
- switch (result)
- {
- // The size is only ever reported back correctly in the case
- // of ERROR_SUCCESS. It will almost always be changed, however.
- case Interop.Errors.ERROR_SUCCESS:
- names.Add(new string(name, 0, nameLength));
- break;
- case Interop.Errors.ERROR_MORE_DATA:
- if (IsPerfDataKey())
- {
- // Enumerating the values for Perf keys always returns
- // ERROR_MORE_DATA, but has a valid name. Buffer does need
- // to be big enough however. 8 characters is the largest
- // known name. The size isn't returned, but the string is
- // null terminated.
- fixed (char* c = &name[0])
- {
- names.Add(new string(c));
- }
- }
- else
- {
- char[] oldName = name;
- int oldLength = oldName.Length;
- name = null;
- ArrayPool<char>.Shared.Return(oldName);
- name = ArrayPool<char>.Shared.Rent(checked(oldLength * 2));
- }
- break;
- default:
- // Throw the error
- Win32Error(result, null);
- break;
- }
-
- // Always set the name length back to the buffer size
- nameLength = name.Length;
- }
- }
- finally
- {
- if (name != null)
- ArrayPool<char>.Shared.Return(name);
- }
-
- return names.ToArray();
- }
-
- /// <summary>Retrieves the specified value. <b>null</b> is returned if the value doesn't exist</summary>
- /// <remarks>
- /// Note that <var>name</var> can be null or "", at which point the
- /// unnamed or default value of this Registry key is returned, if any.
- /// </remarks>
- /// <param name="name">Name of value to retrieve.</param>
- /// <returns>The data associated with the value.</returns>
- public object GetValue(string name)
- {
- return InternalGetValue(name, null, false, true);
- }
-
- /**
- * Retrieves the specified value. <i>defaultValue</i> is returned if the value doesn't exist.
- *
- * Note that <var>name</var> can be null or "", at which point the
- * unnamed or default value of this Registry key is returned, if any.
- * The default values for RegistryKeys are OS-dependent. NT doesn't
- * have them by default, but they can exist and be of any type.
- *
- * @param name Name of value to retrieve.
- * @param defaultValue Value to return if <i>name</i> doesn't exist.
- *
- * @return the data associated with the value.
- */
- public object GetValue(string name, object defaultValue)
- {
- return InternalGetValue(name, defaultValue, false, true);
- }
-
- public object GetValue(string name, object defaultValue, RegistryValueOptions options)
- {
- if (options < RegistryValueOptions.None || options > RegistryValueOptions.DoNotExpandEnvironmentNames)
- {
- throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)options), nameof(options));
- }
- bool doNotExpand = (options == RegistryValueOptions.DoNotExpandEnvironmentNames);
- return InternalGetValue(name, defaultValue, doNotExpand, true);
- }
-
- internal object InternalGetValue(string name, object defaultValue, bool doNotExpand, bool checkSecurity)
- {
- if (checkSecurity)
- {
- // Name can be null! It's the most common use of RegQueryValueEx
- EnsureNotDisposed();
- }
-
- object data = defaultValue;
- int type = 0;
- int datasize = 0;
-
- int ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, (byte[])null, ref datasize);
-
- if (ret != 0)
- {
- if (IsPerfDataKey())
- {
- int size = 65000;
- int sizeInput = size;
-
- int r;
- byte[] blob = new byte[size];
- while (Interop.Errors.ERROR_MORE_DATA == (r = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref sizeInput)))
- {
- if (size == int.MaxValue)
- {
- // ERROR_MORE_DATA was returned however we cannot increase the buffer size beyond int.MaxValue
- Win32Error(r, name);
- }
- else if (size > (int.MaxValue / 2))
- {
- // at this point in the loop "size * 2" would cause an overflow
- size = int.MaxValue;
- }
- else
- {
- size *= 2;
- }
- sizeInput = size;
- blob = new byte[size];
- }
- if (r != 0)
- Win32Error(r, name);
- return blob;
- }
- else
- {
- // For stuff like ERROR_FILE_NOT_FOUND, we want to return null (data).
- // Some OS's returned ERROR_MORE_DATA even in success cases, so we
- // want to continue on through the function.
- if (ret != Interop.Errors.ERROR_MORE_DATA)
- return data;
- }
- }
-
- if (datasize < 0)
- {
- // unexpected code path
- Debug.Fail("[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
- datasize = 0;
- }
-
-
- switch (type)
- {
- case Interop.Advapi32.RegistryValues.REG_NONE:
- case Interop.Advapi32.RegistryValues.REG_DWORD_BIG_ENDIAN:
- case Interop.Advapi32.RegistryValues.REG_BINARY:
- {
- byte[] blob = new byte[datasize];
- ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
- data = blob;
- }
- break;
- case Interop.Advapi32.RegistryValues.REG_QWORD:
- { // also REG_QWORD_LITTLE_ENDIAN
- if (datasize > 8)
- {
- // prevent an AV in the edge case that datasize is larger than sizeof(long)
- goto case Interop.Advapi32.RegistryValues.REG_BINARY;
- }
- long blob = 0;
- Debug.Assert(datasize == 8, "datasize==8");
- // Here, datasize must be 8 when calling this
- ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, ref blob, ref datasize);
-
- data = blob;
- }
- break;
- case Interop.Advapi32.RegistryValues.REG_DWORD:
- { // also REG_DWORD_LITTLE_ENDIAN
- if (datasize > 4)
- {
- // prevent an AV in the edge case that datasize is larger than sizeof(int)
- goto case Interop.Advapi32.RegistryValues.REG_QWORD;
- }
- int blob = 0;
- Debug.Assert(datasize == 4, "datasize==4");
- // Here, datasize must be four when calling this
- ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, ref blob, ref datasize);
-
- data = blob;
- }
- break;
-
- case Interop.Advapi32.RegistryValues.REG_SZ:
- {
- if (datasize % 2 == 1)
- {
- // handle the case where the registry contains an odd-byte length (corrupt data?)
- try
- {
- datasize = checked(datasize + 1);
- }
- catch (OverflowException e)
- {
- throw new IOException(SR.Arg_RegGetOverflowBug, e);
- }
- }
- char[] blob = new char[datasize / 2];
-
- ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
- if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
- {
- data = new string(blob, 0, blob.Length - 1);
- }
- else
- {
- // in the very unlikely case the data is missing null termination,
- // pass in the whole char[] to prevent truncating a character
- data = new string(blob);
- }
- }
- break;
-
- case Interop.Advapi32.RegistryValues.REG_EXPAND_SZ:
- {
- if (datasize % 2 == 1)
- {
- // handle the case where the registry contains an odd-byte length (corrupt data?)
- try
- {
- datasize = checked(datasize + 1);
- }
- catch (OverflowException e)
- {
- throw new IOException(SR.Arg_RegGetOverflowBug, e);
- }
- }
- char[] blob = new char[datasize / 2];
-
- ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
-
- if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
- {
- data = new string(blob, 0, blob.Length - 1);
- }
- else
- {
- // in the very unlikely case the data is missing null termination,
- // pass in the whole char[] to prevent truncating a character
- data = new string(blob);
- }
-
- if (!doNotExpand)
- data = Environment.ExpandEnvironmentVariables((string)data);
- }
- break;
- case Interop.Advapi32.RegistryValues.REG_MULTI_SZ:
- {
- if (datasize % 2 == 1)
- {
- // handle the case where the registry contains an odd-byte length (corrupt data?)
- try
- {
- datasize = checked(datasize + 1);
- }
- catch (OverflowException e)
- {
- throw new IOException(SR.Arg_RegGetOverflowBug, e);
- }
- }
- char[] blob = new char[datasize / 2];
-
- ret = Interop.Advapi32.RegQueryValueEx(_hkey, name, null, ref type, blob, ref datasize);
-
- // make sure the string is null terminated before processing the data
- if (blob.Length > 0 && blob[blob.Length - 1] != (char)0)
- {
- try
- {
- char[] newBlob = new char[checked(blob.Length + 1)];
- for (int i = 0; i < blob.Length; i++)
- {
- newBlob[i] = blob[i];
- }
- newBlob[newBlob.Length - 1] = (char)0;
- blob = newBlob;
- }
- catch (OverflowException e)
- {
- throw new IOException(SR.Arg_RegGetOverflowBug, e);
- }
- blob[blob.Length - 1] = (char)0;
- }
-
-
- IList<string> strings = new List<string>();
- int cur = 0;
- int len = blob.Length;
-
- while (ret == 0 && cur < len)
- {
- int nextNull = cur;
- while (nextNull < len && blob[nextNull] != (char)0)
- {
- nextNull++;
- }
-
- if (nextNull < len)
- {
- Debug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
- if (nextNull - cur > 0)
- {
- strings.Add(new string(blob, cur, nextNull - cur));
- }
- else
- {
- // we found an empty string. But if we're at the end of the data,
- // it's just the extra null terminator.
- if (nextNull != len - 1)
- strings.Add(string.Empty);
- }
- }
- else
- {
- strings.Add(new string(blob, cur, len - cur));
- }
- cur = nextNull + 1;
- }
-
- data = new string[strings.Count];
- strings.CopyTo((string[])data, 0);
- }
- break;
- case Interop.Advapi32.RegistryValues.REG_LINK:
- default:
- break;
- }
-
- return data;
- }
-
- /**
- * Sets the specified value.
- *
- * @param name Name of value to store data in.
- * @param value Data to store.
- */
- public void SetValue(string name, object value)
- {
- SetValue(name, value, RegistryValueKind.Unknown);
- }
-
- public unsafe void SetValue(string name, object value, RegistryValueKind valueKind)
- {
- if (value == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
-
- if (name != null && name.Length > MaxValueLength)
- {
- throw new ArgumentException(SR.Arg_RegValStrLenBug);
- }
-
- if (!Enum.IsDefined(typeof(RegistryValueKind), valueKind))
- throw new ArgumentException(SR.Arg_RegBadKeyKind, nameof(valueKind));
-
- EnsureWriteable();
-
- if (valueKind == RegistryValueKind.Unknown)
- {
- // this is to maintain compatibility with the old way of autodetecting the type.
- // SetValue(string, object) will come through this codepath.
- valueKind = CalculateValueKind(value);
- }
-
- int ret = 0;
- try
- {
- switch (valueKind)
- {
- case RegistryValueKind.ExpandString:
- case RegistryValueKind.String:
- {
- string data = value.ToString();
- ret = Interop.Advapi32.RegSetValueEx(_hkey,
- name,
- 0,
- valueKind,
- data,
- checked(data.Length * 2 + 2));
- break;
- }
-
- case RegistryValueKind.MultiString:
- {
- // Other thread might modify the input array after we calculate the buffer length.
- // Make a copy of the input array to be safe.
- string[] dataStrings = (string[])(((string[])value).Clone());
- int sizeInBytes = 0;
-
- // First determine the size of the array
- //
- for (int i = 0; i < dataStrings.Length; i++)
- {
- if (dataStrings[i] == null)
- {
- throw new ArgumentException(SR.Arg_RegSetStrArrNull);
- }
- sizeInBytes = checked(sizeInBytes + (dataStrings[i].Length + 1) * 2);
- }
- sizeInBytes = checked(sizeInBytes + 2);
-
- byte[] basePtr = new byte[sizeInBytes];
- fixed (byte* b = basePtr)
- {
- IntPtr currentPtr = new IntPtr((void*)b);
-
- // Write out the strings...
- //
- for (int i = 0; i < dataStrings.Length; i++)
- {
- // Assumes that the Strings are always null terminated.
- string.InternalCopy(dataStrings[i], currentPtr, (checked(dataStrings[i].Length * 2)));
- currentPtr = new IntPtr((long)currentPtr + (checked(dataStrings[i].Length * 2)));
- *(char*)(currentPtr.ToPointer()) = '\0';
- currentPtr = new IntPtr((long)currentPtr + 2);
- }
-
- *(char*)(currentPtr.ToPointer()) = '\0';
- currentPtr = new IntPtr((long)currentPtr + 2);
-
- ret = Interop.Advapi32.RegSetValueEx(_hkey,
- name,
- 0,
- RegistryValueKind.MultiString,
- basePtr,
- sizeInBytes);
- }
- break;
- }
-
- case RegistryValueKind.None:
- case RegistryValueKind.Binary:
- byte[] dataBytes = (byte[])value;
- ret = Interop.Advapi32.RegSetValueEx(_hkey,
- name,
- 0,
- (valueKind == RegistryValueKind.None ? Interop.Advapi32.RegistryValues.REG_NONE : RegistryValueKind.Binary),
- dataBytes,
- dataBytes.Length);
- break;
-
- case RegistryValueKind.DWord:
- {
- // We need to use Convert here because we could have a boxed type cannot be
- // unboxed and cast at the same time. I.e. ((int)(object)(short) 5) will fail.
- int data = Convert.ToInt32(value, System.Globalization.CultureInfo.InvariantCulture);
-
- ret = Interop.Advapi32.RegSetValueEx(_hkey,
- name,
- 0,
- RegistryValueKind.DWord,
- ref data,
- 4);
- break;
- }
-
- case RegistryValueKind.QWord:
- {
- long data = Convert.ToInt64(value, System.Globalization.CultureInfo.InvariantCulture);
-
- ret = Interop.Advapi32.RegSetValueEx(_hkey,
- name,
- 0,
- RegistryValueKind.QWord,
- ref data,
- 8);
- break;
- }
- }
- }
- catch (OverflowException)
- {
- throw new ArgumentException(SR.Arg_RegSetMismatchedKind);
- }
- catch (InvalidOperationException)
- {
- throw new ArgumentException(SR.Arg_RegSetMismatchedKind);
- }
- catch (FormatException)
- {
- throw new ArgumentException(SR.Arg_RegSetMismatchedKind);
- }
- catch (InvalidCastException)
- {
- throw new ArgumentException(SR.Arg_RegSetMismatchedKind);
- }
-
- if (ret == 0)
- {
- SetDirty();
- }
- else
- Win32Error(ret, null);
- }
-
- private RegistryValueKind CalculateValueKind(object value)
- {
- // This logic matches what used to be in SetValue(string name, object value) in the v1.0 and v1.1 days.
- // Even though we could add detection for an int64 in here, we want to maintain compatibility with the
- // old behavior.
- if (value is int)
- return RegistryValueKind.DWord;
- else if (value is Array)
- {
- if (value is byte[])
- return RegistryValueKind.Binary;
- else if (value is string[])
- return RegistryValueKind.MultiString;
- else
- throw new ArgumentException(SR.Format(SR.Arg_RegSetBadArrType, value.GetType().Name));
- }
- else
- return RegistryValueKind.String;
- }
-
- /**
- * After calling GetLastWin32Error(), it clears the last error field,
- * so you must save the HResult and pass it to this method. This method
- * will determine the appropriate exception to throw dependent on your
- * error, and depending on the error, insert a string into the message
- * gotten from the ResourceManager.
- */
- internal void Win32Error(int errorCode, string str)
- {
- switch (errorCode)
- {
- case Interop.Errors.ERROR_ACCESS_DENIED:
- if (str != null)
- throw new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_RegistryKeyGeneric_Key, str));
- else
- throw new UnauthorizedAccessException();
-
- case Interop.Errors.ERROR_INVALID_HANDLE:
- /**
- * For normal RegistryKey instances we dispose the SafeRegHandle and throw IOException.
- * However, for HKEY_PERFORMANCE_DATA (on a local or remote machine) we avoid disposing the
- * SafeRegHandle and only throw the IOException. This is to workaround reentrancy issues
- * in PerformanceCounter.NextValue() where the API could throw {NullReference, ObjectDisposed, ArgumentNull}Exception
- * on reentrant calls because of this error code path in RegistryKey
- *
- * Normally we'd make our caller synchronize access to a shared RegistryKey instead of doing something like this,
- * however we shipped PerformanceCounter.NextValue() un-synchronized in v2.0RTM and customers have taken a dependency on
- * this behavior (being able to simultaneously query multiple remote-machine counters on multiple threads, instead of
- * having serialized access).
- */
- if (!IsPerfDataKey())
- {
- _hkey.SetHandleAsInvalid();
- _hkey = null;
- }
- goto default;
-
- case Interop.Errors.ERROR_FILE_NOT_FOUND:
- throw new IOException(SR.Arg_RegKeyNotFound, errorCode);
-
- default:
- throw new IOException(Interop.Kernel32.GetMessage(errorCode), errorCode);
- }
- }
-
- internal static string FixupName(string name)
- {
- Debug.Assert(name != null, "[FixupName]name!=null");
- if (!name.Contains('\\'))
- return name;
-
- StringBuilder sb = new StringBuilder(name);
- FixupPath(sb);
- int temp = sb.Length - 1;
- if (temp >= 0 && sb[temp] == '\\') // Remove trailing slash
- sb.Length = temp;
- return sb.ToString();
- }
-
- private void EnsureNotDisposed()
- {
- if (_hkey == null)
- {
- throw new ObjectDisposedException(_keyName, SR.ObjectDisposed_RegKeyClosed);
- }
- }
-
- private void EnsureWriteable()
- {
- EnsureNotDisposed();
- if (!IsWritable())
- {
- throw new UnauthorizedAccessException(SR.UnauthorizedAccess_RegistryNoWrite);
- }
- }
-
- private static int GetRegistryKeyAccess(bool isWritable)
- {
- int winAccess;
- if (!isWritable)
- {
- winAccess = Interop.Advapi32.RegistryOperations.KEY_READ;
- }
- else
- {
- winAccess = Interop.Advapi32.RegistryOperations.KEY_READ | Interop.Advapi32.RegistryOperations.KEY_WRITE;
- }
-
- return winAccess;
- }
-
- private RegistryKeyPermissionCheck GetSubKeyPermissonCheck(bool subkeyWritable)
- {
- if (checkMode == RegistryKeyPermissionCheck.Default)
- {
- return checkMode;
- }
-
- if (subkeyWritable)
- {
- return RegistryKeyPermissionCheck.ReadWriteSubTree;
- }
- else
- {
- return RegistryKeyPermissionCheck.ReadSubTree;
- }
- }
-
- private static void ValidateKeyName(string name)
- {
- if (name == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.name);
- }
-
- int nextSlash = name.IndexOf("\\", StringComparison.OrdinalIgnoreCase);
- int current = 0;
- while (nextSlash != -1)
- {
- if ((nextSlash - current) > MaxKeyLength)
- throw new ArgumentException(SR.Arg_RegKeyStrLenBug);
-
- current = nextSlash + 1;
- nextSlash = name.IndexOf("\\", current, StringComparison.OrdinalIgnoreCase);
- }
-
- if ((name.Length - current) > MaxKeyLength)
- throw new ArgumentException(SR.Arg_RegKeyStrLenBug);
- }
-
- private static void ValidateKeyView(RegistryView view)
- {
- if (view != RegistryView.Default && view != RegistryView.Registry32 && view != RegistryView.Registry64)
- {
- throw new ArgumentException(SR.Argument_InvalidRegistryViewCheck, nameof(view));
- }
- }
- }
-
- // the name for this API is meant to mimic FileMode, which has similar values
-
- internal enum RegistryKeyPermissionCheck
- {
- Default = 0,
- ReadSubTree = 1,
- ReadWriteSubTree = 2
- }
-}
diff --git a/src/System.Private.CoreLib/src/System/Environment.cs b/src/System.Private.CoreLib/src/System/Environment.cs
index 1b5206567e..4c65d77089 100644
--- a/src/System.Private.CoreLib/src/System/Environment.cs
+++ b/src/System.Private.CoreLib/src/System/Environment.cs
@@ -12,26 +12,21 @@
**
============================================================*/
+using Microsoft.Win32;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+#if FEATURE_WIN32_REGISTRY
+using Internal.Win32;
+#endif
+
namespace System
{
- using System.Buffers;
- using System.IO;
- using System.Security;
- using System.Resources;
- using System.Globalization;
- using System.Collections;
- using System.Collections.Generic;
- using System.Text;
- using System.Configuration.Assemblies;
- using System.Runtime.InteropServices;
- using System.Reflection;
- using System.Diagnostics;
- using Microsoft.Win32;
- using System.Runtime.CompilerServices;
- using System.Threading;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.Versioning;
-
public enum EnvironmentVariableTarget
{
Process = 0,