From 140f71b6164e698eed4e4f5776607bf1be97f438 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 10 Sep 2018 23:33:05 -0700 Subject: Move more registry files to shared partition --- .../src/Interop/Windows/Interop.Libraries.cs | 4 - .../Windows/Advapi32/Interop.RegFlushKey.cs | 15 +++ .../shared/Microsoft/Win32/RegistryOptions.cs | 20 +++ .../shared/Microsoft/Win32/RegistryValueOptions.cs | 20 +++ .../shared/System.Private.CoreLib.Shared.projitems | 22 ++-- .../Security/AccessControl/RegistryRights.cs | 42 +++++++ .../src/Microsoft/Win32/RegistryKey.Windows.cs | 138 ++++++++++++++------- .../src/Microsoft/Win32/RegistryKey.cs | 12 -- .../src/Microsoft/Win32/RegistryOptions.cs | 20 --- .../src/System.Private.CoreLib.csproj | 2 - .../Security/AccessControl/RegistryRights.cs | 42 ------- 11 files changed, 205 insertions(+), 132 deletions(-) create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegFlushKey.cs create mode 100644 src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryOptions.cs create mode 100644 src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueOptions.cs create mode 100644 src/System.Private.CoreLib/shared/System/Security/AccessControl/RegistryRights.cs delete mode 100644 src/System.Private.CoreLib/src/Microsoft/Win32/RegistryOptions.cs delete mode 100644 src/System.Private.CoreLib/src/System/Security/AccessControl/RegistryRights.cs diff --git a/src/Common/src/Interop/Windows/Interop.Libraries.cs b/src/Common/src/Interop/Windows/Interop.Libraries.cs index 8536bc367..68a50eadd 100644 --- a/src/Common/src/Interop/Windows/Interop.Libraries.cs +++ b/src/Common/src/Interop/Windows/Interop.Libraries.cs @@ -6,9 +6,6 @@ internal static partial class Interop { internal static partial class Libraries { - internal const string CoreFile_L1 = "api-ms-win-core-file-l1-1-0.dll"; - internal const string CoreFile_L1_2 = "api-ms-win-core-file-l1-2-0.dll"; - internal const string CoreFile_L2 = "api-ms-win-core-file-l2-1-0.dll"; internal const string ErrorHandling = "api-ms-win-core-errorhandling-l1-1-0.dll"; internal const string Handle = "api-ms-win-core-handle-l1-1-0.dll"; internal const string IO = "api-ms-win-core-io-l1-1-0.dll"; @@ -17,7 +14,6 @@ internal static partial class Interop internal const string ProcessThreads = "api-ms-win-core-processthreads-l1-1-0.dll"; internal const string RealTime = "api-ms-win-core-realtime-l1-1-0.dll"; internal const string SysInfo = "api-ms-win-core-sysinfo-l1-2-0.dll"; - internal const string Registry_L1 = "api-ms-win-core-registry-l1-1-0.dll"; internal const string ThreadPool = "api-ms-win-core-threadpool-l1-2-0.dll"; internal const string Localization = "api-ms-win-core-localization-l1-2-1.dll"; } 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 new file mode 100644 index 000000000..8f72798f8 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Advapi32/Interop.RegFlushKey.cs @@ -0,0 +1,15 @@ +// 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.SafeHandles; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Advapi32 + { + [DllImport(Libraries.Advapi32)] + internal static extern int RegFlushKey(SafeRegistryHandle hKey); + } +} diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryOptions.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryOptions.cs new file mode 100644 index 000000000..201a6df0e --- /dev/null +++ b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryOptions.cs @@ -0,0 +1,20 @@ +// 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/RegistryValueOptions.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueOptions.cs new file mode 100644 index 000000000..7d9b6c403 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Microsoft/Win32/RegistryValueOptions.cs @@ -0,0 +1,20 @@ +// 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/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index eae701602..769b21609 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -801,35 +801,39 @@ - - + + + - - - + + - - - + + + + - + + + + diff --git a/src/System.Private.CoreLib/shared/System/Security/AccessControl/RegistryRights.cs b/src/System.Private.CoreLib/shared/System/Security/AccessControl/RegistryRights.cs new file mode 100644 index 000000000..729e2f6b5 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Security/AccessControl/RegistryRights.cs @@ -0,0 +1,42 @@ +// 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/src/Microsoft/Win32/RegistryKey.Windows.cs b/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.Windows.cs index a8fb1c187..b9221327e 100644 --- a/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.Windows.cs +++ b/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.Windows.cs @@ -4,6 +4,7 @@ using Microsoft.Win32.SafeHandles; using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -285,36 +286,45 @@ namespace Microsoft.Win32 return subkeys; } - private unsafe string[] InternalGetSubKeyNamesCore(int subkeys) + private string[] InternalGetSubKeyNamesCore(int subkeys) { - string[] names = new string[subkeys]; - char[] name = new char[MaxKeyLength + 1]; + var names = new List(subkeys); + char[] name = ArrayPool.Shared.Rent(MaxKeyLength + 1); - int namelen; - - fixed (char* namePtr = &name[0]) + try { - for (int i = 0; i < subkeys; i++) + 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) { - namelen = name.Length; // Don't remove this. The API's doesn't work if this is not properly initialized. - int ret = Interop.Advapi32.RegEnumKeyEx(_hkey, - i, - namePtr, - ref namelen, - null, - null, - null, - null); - if (ret != 0) + switch (result) { - Win32Error(ret, null); + case Interop.Errors.ERROR_SUCCESS: + names.Add(new string(name, 0, nameLength)); + nameLength = name.Length; + break; + default: + // Throw the error + Win32Error(result, null); + break; } - - names[i] = new string(namePtr); } } + finally + { + ArrayPool.Shared.Return(name); + } - return names; + return names.ToArray(); } private int InternalValueCountCore() @@ -345,37 +355,79 @@ namespace Microsoft.Win32 /// All value names. private unsafe string[] GetValueNamesCore(int values) { - string[] names = new string[values]; - char[] name = new char[MaxValueLength + 1]; - int namelen; + var names = new List(values); + + // 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.Shared.Rent(100); - fixed (char* namePtr = &name[0]) + try { - for (int i = 0; i < values; i++) + 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) { - namelen = name.Length; - - int ret = Interop.Advapi32.RegEnumValue(_hkey, - i, - namePtr, - ref namelen, - IntPtr.Zero, - null, - null, - null); - - if (ret != 0) + switch (result) { - // ignore ERROR_MORE_DATA if we're querying HKEY_PERFORMANCE_DATA - if (!(IsPerfDataKey() && ret == Interop.Errors.ERROR_MORE_DATA)) - Win32Error(ret, null); + // 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.Shared.Return(oldName); + name = ArrayPool.Shared.Rent(checked(oldLength * 2)); + } + break; + default: + // Throw the error + Win32Error(result, null); + break; } - names[i] = new string(namePtr); + // Always set the name length back to the buffer size + nameLength = name.Length; } } + finally + { + if (name != null) + ArrayPool.Shared.Return(name); + } - return names; + return names.ToArray(); } private object InternalGetValueCore(string name, object defaultValue, bool doNotExpand) diff --git a/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.cs b/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.cs index 74d0ed362..ecf8376ed 100644 --- a/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.cs +++ b/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryKey.cs @@ -562,16 +562,4 @@ namespace Microsoft.Win32 // Its not being used anywhere. public void SetValue(string name, object value, RegistryValueKind valueKind) { } } - - [Flags] -#if REGISTRY_ASSEMBLY - public -#else - internal -#endif - enum RegistryValueOptions - { - None = 0, - DoNotExpandEnvironmentNames = 1 - } } diff --git a/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryOptions.cs b/src/System.Private.CoreLib/src/Microsoft/Win32/RegistryOptions.cs deleted file mode 100644 index 201a6df0e..000000000 --- a/src/System.Private.CoreLib/src/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/src/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 88c6d2f02..923a7bfd4 100644 --- a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -349,9 +349,7 @@ - - Interop\Windows\mincore\Interop.ExitProcess.cs diff --git a/src/System.Private.CoreLib/src/System/Security/AccessControl/RegistryRights.cs b/src/System.Private.CoreLib/src/System/Security/AccessControl/RegistryRights.cs deleted file mode 100644 index 729e2f6b5..000000000 --- a/src/System.Private.CoreLib/src/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 - } -} -- cgit v1.2.3