Revert "Strip out unused reg code. (dotnet/coreclr#10741)"
authordanmosemsft <danmose@microsoft.com>
Fri, 14 Apr 2017 22:53:33 +0000 (15:53 -0700)
committerdanmosemsft <danmose@microsoft.com>
Fri, 14 Apr 2017 22:53:33 +0000 (15:53 -0700)
This reverts commit dotnet/coreclr@ed4f594abf41a71b126152bb8755051d0831e12d.

Commit migrated from https://github.com/dotnet/coreclr/commit/368b35097bb12ef8ec5df64103303c7488d82dd7

src/coreclr/src/mscorlib/System.Private.CoreLib.csproj
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
src/coreclr/src/mscorlib/src/Microsoft/Win32/Registry.cs
src/coreclr/src/mscorlib/src/Microsoft/Win32/RegistryKey.cs
src/coreclr/src/mscorlib/src/Microsoft/Win32/RegistryValueKind.cs
src/coreclr/src/mscorlib/src/Microsoft/Win32/RegistryView.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/src/Microsoft/Win32/SafeHandles/SafeRegistryHandle.cs
src/coreclr/src/mscorlib/src/System/Environment.cs
src/coreclr/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs
src/coreclr/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs
src/coreclr/src/mscorlib/src/System/TimeZoneInfo.Win32.cs

index 3a0917f..4541ef8 100644 (file)
   <PropertyGroup Condition="'$(OsEnvironment)' == 'Unix'">
     <DebugType>portable</DebugType>
   </PropertyGroup>
+
   <PropertyGroup Condition="'$(TargetsOSX)' == 'true'">
     <DefineConstants>PLATFORM_OSX;$(DefineConstants)</DefineConstants>
   </PropertyGroup>
+
   <!-- Assembly attributes -->
   <PropertyGroup>
     <AssemblyName>System.Private.CoreLib</AssemblyName>
     <Compile Condition="'$(FeatureWin32Registry)' == 'true'" Include="$(BclSourcesRoot)\Microsoft\Win32\Registry.cs" />
     <Compile Condition="'$(FeatureWin32Registry)' == 'true'" Include="$(BclSourcesRoot)\Microsoft\Win32\RegistryKey.cs" />
     <Compile Condition="'$(FeatureWin32Registry)' == 'true'" Include="$(BclSourcesRoot)\Microsoft\Win32\RegistryValueKind.cs" />
+    <Compile Condition="'$(FeatureWin32Registry)' == 'true'" Include="$(BclSourcesRoot)\Microsoft\Win32\RegistryView.cs" />
     <Compile Condition="'$(FeatureClassicCominterop)' == 'true'" Include="$(BclSourcesRoot)\Microsoft\Win32\OAVariantLib.cs" />
   </ItemGroup>
   <ItemGroup>
     <Win32Resource Condition="'$(GenerateNativeVersionInfo)'=='true'">$(IntermediateOutputPath)\System.Private.CoreLib.res</Win32Resource>
   </PropertyGroup>
   <Import Project="GenerateCompilerResponseFile.targets" />
-</Project>
\ No newline at end of file
+</Project>
index 57d550d..e18574c 100644 (file)
@@ -555,21 +555,21 @@ namespace System.Diagnostics.Tracing
             {
 #if (!ES_BUILD_PCL && !ES_BUILD_PN && !FEATURE_PAL)
                 string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}";
-                if (Marshal.SizeOf(typeof(IntPtr)) == 8)
-                    regKey = @"Software" + @"\Wow6432Node" + regKey;
+                if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8)
+                    regKey = @"HKEY_LOCAL_MACHINE\Software" + @"\Wow6432Node" + regKey;
                 else
-                    regKey = @"Software" + regKey;
+                    regKey = @"HKEY_LOCAL_MACHINE\Software" + regKey;
 
                 string valueName = "ControllerData_Session_" + etwSessionId.ToString(CultureInfo.InvariantCulture);
 
-                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(regKey, writable: false))
-                {
-                    data = key.GetValue(valueName) as byte[];
-                }
-
+                // we need to assert this permission for partial trust scenarios
+#if !CORECLR
+                (new RegistryPermission(RegistryPermissionAccess.Read, regKey)).Assert();
+#endif
+                data = Microsoft.Win32.Registry.GetValue(regKey, valueName, null) as byte[];
                 if (data != null)
                 {
-                    // We only used the persisted data from the registry for updates.
+                    // We only used the persisted data from the registry for updates.   
                     command = ControllerCommand.Update;
                     return true;
                 }
index aa2dd9b..d0dbb0f 100644 (file)
 // 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.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
 namespace Microsoft.Win32
 {
+    /**
+     * Registry encapsulation. Contains members representing all top level system
+     * keys.
+     *
+     * @security(checkClassLinking=on)
+     */
+    //This class contains only static members and does not need to be serializable.
     internal static class Registry
     {
-        public static readonly RegistryKey CurrentUser = RegistryKey.CurrentUser;
-        public static readonly RegistryKey LocalMachine = RegistryKey.LocalMachine;
+        /**
+         * Current User Key.
+         * 
+         * This key should be used as the root for all user specific settings.
+         */
+        public static readonly RegistryKey CurrentUser = RegistryKey.GetBaseKey(RegistryKey.HKEY_CURRENT_USER);
+
+        /**
+         * Local Machine Key.
+         * 
+         * This key should be used as the root for all machine specific settings.
+         */
+        public static readonly RegistryKey LocalMachine = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE);
+
+        /**
+         * Classes Root Key.
+         * 
+         * This is the root key of class information.
+         */
+        public static readonly RegistryKey ClassesRoot = RegistryKey.GetBaseKey(RegistryKey.HKEY_CLASSES_ROOT);
+
+        /**
+         * Users Root Key.
+         * 
+         * This is the root of users.
+         */
+        public static readonly RegistryKey Users = RegistryKey.GetBaseKey(RegistryKey.HKEY_USERS);
+
+        /**
+         * Performance Root Key.
+         * 
+         * This is where dynamic performance data is stored on NT.
+         */
+        public static readonly RegistryKey PerformanceData = RegistryKey.GetBaseKey(RegistryKey.HKEY_PERFORMANCE_DATA);
+
+        /**
+         * Current Config Root Key.
+         * 
+         * This is where current configuration information is stored.
+         */
+        public static readonly RegistryKey CurrentConfig = RegistryKey.GetBaseKey(RegistryKey.HKEY_CURRENT_CONFIG);
+
+        //
+        // Following function will 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. 
+        //
+        private static RegistryKey GetBaseKeyFromKeyName(string keyName, out string subKeyName)
+        {
+            if (keyName == null)
+            {
+                throw new ArgumentNullException(nameof(keyName));
+            }
+
+            string basekeyName;
+            int i = keyName.IndexOf('\\');
+            if (i != -1)
+            {
+                basekeyName = keyName.Substring(0, i).ToUpper(System.Globalization.CultureInfo.InvariantCulture);
+            }
+            else
+            {
+                basekeyName = keyName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
+            }
+            RegistryKey basekey = null;
+
+            switch (basekeyName)
+            {
+                case "HKEY_CURRENT_USER":
+                    basekey = Registry.CurrentUser;
+                    break;
+                case "HKEY_LOCAL_MACHINE":
+                    basekey = Registry.LocalMachine;
+                    break;
+                case "HKEY_CLASSES_ROOT":
+                    basekey = Registry.ClassesRoot;
+                    break;
+                case "HKEY_USERS":
+                    basekey = Registry.Users;
+                    break;
+                case "HKEY_PERFORMANCE_DATA":
+                    basekey = Registry.PerformanceData;
+                    break;
+                case "HKEY_CURRENT_CONFIG":
+                    basekey = Registry.CurrentConfig;
+                    break;
+                default:
+                    throw new ArgumentException(SR.Format(SR.Arg_RegInvalidKeyName, nameof(keyName)));
+            }
+            if (i == -1 || i == keyName.Length)
+            {
+                subKeyName = string.Empty;
+            }
+            else
+            {
+                subKeyName = keyName.Substring(i + 1, keyName.Length - i - 1);
+            }
+            return basekey;
+        }
+
+        public static object GetValue(string keyName, string valueName, object defaultValue)
+        {
+            string subKeyName;
+            RegistryKey basekey = GetBaseKeyFromKeyName(keyName, out subKeyName);
+            BCLDebug.Assert(basekey != null, "basekey can't be null.");
+            RegistryKey key = basekey.OpenSubKey(subKeyName);
+            if (key == null)
+            { // if the key doesn't exist, do nothing
+                return null;
+            }
+            try
+            {
+                return key.GetValue(valueName, defaultValue);
+            }
+            finally
+            {
+                key.Close();
+            }
+        }
     }
 }
 
index e39b959..521ea65 100644 (file)
@@ -2,6 +2,28 @@
 // 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 (possibly Whidbey M3?).  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
@@ -30,28 +52,34 @@ using Microsoft.Win32.SafeHandles;
 using System;
 using System.Buffers;
 using System.Collections.Generic;
-using System.Diagnostics;
+using System.Diagnostics.Contracts;
 using System.IO;
+using System.Text;
 
 namespace Microsoft.Win32
 {
     /**
      * Registry encapsulation. To get an instance of a RegistryKey use the
      * Registry class's static members then call OpenSubKey.
+     *
+     * @see Registry
+     * @security(checkDllCalls=off)
+     * @security(checkClassLinking=on)
      */
     internal sealed class RegistryKey : MarshalByRefObject, IDisposable
     {
-        // Use the public Registry.CurrentUser
-        internal static readonly RegistryKey CurrentUser =
-            GetBaseKey(new IntPtr(unchecked((int)0x80000001)), "HKEY_CURRENT_USER");
-
-        // Use the public Registry.LocalMachine
-        internal static readonly RegistryKey LocalMachine =
-            GetBaseKey(new IntPtr(unchecked((int)0x80000002)), "HKEY_LOCAL_MACHINE");
-
         // We could use const here, if C# supported ELEMENT_TYPE_I fully.
-        private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));
-        private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
+        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));
+
+        // Dirty indicates that we have munged data that should be potentially
+        // written to disk.
+        //
+        private const int STATE_DIRTY = 0x0001;
 
         // SystemKey indicates that this is a "SYSTEMKEY" and shouldn't be "opened"
         // or "closed".
@@ -62,6 +90,20 @@ namespace Microsoft.Win32
         //
         private const int STATE_WRITEACCESS = 0x0004;
 
+        // Indicates if this key is for HKEY_PERFORMANCE_DATA
+        private const int STATE_PERF_DATA = 0x0008;
+
+        // Names of keys.  This array must be in the same order as the HKEY values listed above.
+        //
+        private static readonly String[] 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
@@ -71,7 +113,31 @@ namespace Microsoft.Win32
 
         private volatile SafeRegistryHandle hkey = null;
         private volatile int state = 0;
-        private volatile string keyName;
+        private volatile String keyName;
+        private volatile bool remoteKey = false;
+        private volatile RegistryKeyPermissionCheck checkMode;
+        private volatile RegistryView regView = RegistryView.Default;
+
+        /**
+         * RegistryInternalCheck values.  Useful only for CheckPermission
+         */
+        private enum RegistryInternalCheck
+        {
+            CheckSubKeyWritePermission = 0,
+            CheckSubKeyReadPermission = 1,
+            CheckSubKeyCreatePermission = 2,
+            CheckSubTreeReadPermission = 3,
+            CheckSubTreeWritePermission = 4,
+            CheckSubTreeReadWritePermission = 5,
+            CheckValueWritePermission = 6,
+            CheckValueCreatePermission = 7,
+            CheckValueReadPermission = 8,
+            CheckKeyReadPermission = 9,
+            CheckSubTreePermission = 10,
+            CheckOpenSubKeyWithWritablePermission = 11,
+            CheckOpenSubKeyPermission = 12
+        };
+
 
         /**
          * Creates a RegistryKey.
@@ -82,10 +148,12 @@ namespace Microsoft.Win32
          * 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.
          */
-        private RegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey)
+        private RegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey, bool remoteKey, bool isPerfData, RegistryView view)
         {
             this.hkey = hkey;
             keyName = "";
+            this.remoteKey = remoteKey;
+            regView = view;
             if (systemkey)
             {
                 state |= STATE_SYSTEMKEY;
@@ -94,6 +162,17 @@ namespace Microsoft.Win32
             {
                 state |= STATE_WRITEACCESS;
             }
+            if (isPerfData)
+                state |= STATE_PERF_DATA;
+            ValidateKeyView(view);
+        }
+
+        /**
+         * Closes this key, flushes it to disk if the contents have been modified.
+         */
+        public void Close()
+        {
+            Dispose(true);
         }
 
         private void Dispose(bool disposing)
@@ -115,6 +194,21 @@ namespace Microsoft.Win32
                         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. 
+                    SafeRegistryHandle.RegCloseKey(RegistryKey.HKEY_PERFORMANCE_DATA);
+                }
             }
         }
 
@@ -123,13 +217,13 @@ namespace Microsoft.Win32
             Dispose(true);
         }
 
-        public void DeleteValue(string name, bool throwOnMissingValue)
+        public void DeleteValue(String name, bool throwOnMissingValue)
         {
             EnsureWriteable();
             int errorCode = Win32Native.RegDeleteValue(hkey, name);
 
             //
-            // From windows 2003 server, if the name is too long we will get error code ERROR_FILENAME_EXCED_RANGE
+            // 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 == Win32Native.ERROR_FILE_NOT_FOUND || errorCode == Win32Native.ERROR_FILENAME_EXCED_RANGE)
@@ -138,44 +232,77 @@ namespace Microsoft.Win32
                 {
                     ThrowHelper.ThrowArgumentException(ExceptionResource.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);
+            BCLDebug.Correctness(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 GetBaseKey(IntPtr hKey)
+        {
+            return GetBaseKey(hKey, RegistryView.Default);
         }
 
-        private static RegistryKey GetBaseKey(IntPtr hKey, string keyName)
+        internal static RegistryKey GetBaseKey(IntPtr hKey, RegistryView view)
         {
-            SafeRegistryHandle srh = new SafeRegistryHandle(hKey, ownsHandle: false);
+            int index = ((int)hKey) & 0x0FFFFFFF;
+            BCLDebug.Assert(index >= 0 && index < hkeyNames.Length, "index is out of range!");
+            BCLDebug.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);
-            key.keyName = keyName;
+            RegistryKey key = new RegistryKey(srh, true, true, false, isPerf, view);
+            key.checkMode = RegistryKeyPermissionCheck.Default;
+            key.keyName = hkeyNames[index];
             return key;
         }
 
-        /// <summary>
-        /// Retrieves a subkey or null if the operation failed.
-        /// </summary>
-        /// <param name="writable">True to open writable, otherwise opens the key read-only.</param>
+        /**
+         * 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 = Win32Native.RegOpenKeyEx(hkey,
                 name,
                 0,
-                writable ? Win32Native.KEY_READ | Win32Native.KEY_WRITE : Win32Native.KEY_READ,
+                GetRegistryKeyAccess(writable) | (int)regView,
                 out result);
 
             if (ret == 0 && !result.IsInvalid)
             {
-                RegistryKey key = new RegistryKey(result, writable, false);
+                RegistryKey key = new RegistryKey(result, writable, false, remoteKey, false, regView);
+                key.checkMode = GetSubKeyPermissonCheck(writable);
                 key.keyName = keyName + "\\" + name;
                 return key;
             }
@@ -191,6 +318,41 @@ namespace Microsoft.Win32
             return null;
         }
 
+        // This required no security checks. This is to get around the Deleting SubKeys which only require
+        // write permission. They call OpenSubKey which required read. Now instead call this function w/o security checks
+        internal RegistryKey InternalOpenSubKey(String name, bool writable)
+        {
+            ValidateKeyName(name);
+            EnsureNotDisposed();
+
+            SafeRegistryHandle result = null;
+            int ret = Win32Native.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.keyName = keyName + "\\" + name;
+                return key;
+            }
+            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>
@@ -319,6 +481,22 @@ namespace Microsoft.Win32
         }
 
         /**
+         * Retrieves the specified value. <b>null</b> 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.
+         *
+         * @param name Name of value to retrieve.
+         *
+         * @return the data associated with the value.
+         */
+        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
@@ -333,11 +511,30 @@ namespace Microsoft.Win32
          *
          * @return the data associated with the value.
          */
-        public object GetValue(string name, object defaultValue = null, bool doNotExpand = false)
+        public Object GetValue(String name, Object defaultValue)
         {
-            EnsureNotDisposed();
+            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;
+            Object data = defaultValue;
             int type = 0;
             int datasize = 0;
 
@@ -345,20 +542,54 @@ namespace Microsoft.Win32
 
             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 != Win32Native.ERROR_MORE_DATA)
-                    return data;
+                if (IsPerfDataKey())
+                {
+                    int size = 65000;
+                    int sizeInput = size;
+
+                    int r;
+                    byte[] blob = new byte[size];
+                    while (Win32Native.ERROR_MORE_DATA == (r = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref sizeInput)))
+                    {
+                        if (size == Int32.MaxValue)
+                        {
+                            // ERROR_MORE_DATA was returned however we cannot increase the buffer size beyond Int32.MaxValue
+                            Win32Error(r, name);
+                        }
+                        else if (size > (Int32.MaxValue / 2))
+                        {
+                            // at this point in the loop "size * 2" would cause an overflow
+                            size = Int32.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 != Win32Native.ERROR_MORE_DATA)
+                        return data;
+                }
             }
 
             if (datasize < 0)
             {
                 // unexpected code path
-                Debug.Assert(false, "[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
+                BCLDebug.Assert(false, "[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
                 datasize = 0;
             }
 
+
             switch (type)
             {
                 case Win32Native.REG_NONE:
@@ -378,7 +609,7 @@ namespace Microsoft.Win32
                             goto case Win32Native.REG_BINARY;
                         }
                         long blob = 0;
-                        Debug.Assert(datasize == 8, "datasize==8");
+                        BCLDebug.Assert(datasize == 8, "datasize==8");
                         // Here, datasize must be 8 when calling this
                         ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, ref blob, ref datasize);
 
@@ -393,7 +624,7 @@ namespace Microsoft.Win32
                             goto case Win32Native.REG_QWORD;
                         }
                         int blob = 0;
-                        Debug.Assert(datasize == 4, "datasize==4");
+                        BCLDebug.Assert(datasize == 4, "datasize==4");
                         // Here, datasize must be four when calling this
                         ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, ref blob, ref datasize);
 
@@ -420,13 +651,13 @@ namespace Microsoft.Win32
                         ret = Win32Native.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);
+                            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 = new String(blob);
                         }
                     }
                     break;
@@ -451,17 +682,17 @@ namespace Microsoft.Win32
 
                         if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
                         {
-                            data = new string(blob, 0, blob.Length - 1);
+                            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 = new String(blob);
                         }
 
                         if (!doNotExpand)
-                            data = Environment.ExpandEnvironmentVariables((string)data);
+                            data = Environment.ExpandEnvironmentVariables((String)data);
                     }
                     break;
                 case Win32Native.REG_MULTI_SZ:
@@ -502,7 +733,8 @@ namespace Microsoft.Win32
                             blob[blob.Length - 1] = (char)0;
                         }
 
-                        IList<string> strings = new List<string>();
+
+                        IList<String> strings = new List<String>();
                         int cur = 0;
                         int len = blob.Length;
 
@@ -516,28 +748,28 @@ namespace Microsoft.Win32
 
                             if (nextNull < len)
                             {
-                                Debug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
+                                BCLDebug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
                                 if (nextNull - cur > 0)
                                 {
-                                    strings.Add(new string(blob, cur, nextNull - cur));
+                                    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);
+                                        strings.Add(String.Empty);
                                 }
                             }
                             else
                             {
-                                strings.Add(new string(blob, cur, len - cur));
+                                strings.Add(new String(blob, cur, len - cur));
                             }
                             cur = nextNull + 1;
                         }
 
-                        data = new string[strings.Count];
-                        strings.CopyTo((string[])data, 0);
+                        data = new String[strings.Count];
+                        strings.CopyTo((String[])data, 0);
                     }
                     break;
                 case Win32Native.REG_LINK:
@@ -560,10 +792,26 @@ namespace Microsoft.Win32
 
         private bool IsPerfDataKey()
         {
-            return false;
+            return (state & STATE_PERF_DATA) != 0;
+        }
+
+        private void SetDirty()
+        {
+            state |= STATE_DIRTY;
+        }
+
+        /**
+         * 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 SetStringValue(string name, string value)
+        public unsafe void SetValue(String name, Object value, RegistryValueKind valueKind)
         {
             if (value == null)
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
@@ -573,17 +821,167 @@ namespace Microsoft.Win32
                 throw new ArgumentException(SR.Arg_RegValStrLenBug);
             }
 
+            if (!Enum.IsDefined(typeof(RegistryValueKind), valueKind))
+                throw new ArgumentException(SR.Arg_RegBadKeyKind, nameof(valueKind));
+
             EnsureWriteable();
 
-            int result = Win32Native.RegSetValueEx(hkey,
-                name,
-                0,
-                RegistryValueKind.String,
-                value,
-                checked(value.Length * 2 + 2));
+            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 = Win32Native.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)
+                                {
+                                    ThrowHelper.ThrowArgumentException(ExceptionResource.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 = Win32Native.RegSetValueEx(hkey,
+                                    name,
+                                    0,
+                                    RegistryValueKind.MultiString,
+                                    basePtr,
+                                    sizeInBytes);
+                            }
+                            break;
+                        }
+
+                    case RegistryValueKind.None:
+                    case RegistryValueKind.Binary:
+                        byte[] dataBytes = (byte[])value;
+                        ret = Win32Native.RegSetValueEx(hkey,
+                            name,
+                            0,
+                            (valueKind == RegistryValueKind.None ? Win32Native.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 = Win32Native.RegSetValueEx(hkey,
+                                name,
+                                0,
+                                RegistryValueKind.DWord,
+                                ref data,
+                                4);
+                            break;
+                        }
 
-            if (result != 0)
-                Win32Error(result, null);
+                    case RegistryValueKind.QWord:
+                        {
+                            long data = Convert.ToInt64(value, System.Globalization.CultureInfo.InvariantCulture);
+
+                            ret = Win32Native.RegSetValueEx(hkey,
+                                name,
+                                0,
+                                RegistryValueKind.QWord,
+                                ref data,
+                                8);
+                            break;
+                        }
+                }
+            }
+            catch (OverflowException)
+            {
+                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegSetMismatchedKind);
+            }
+            catch (InvalidOperationException)
+            {
+                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegSetMismatchedKind);
+            }
+            catch (FormatException)
+            {
+                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegSetMismatchedKind);
+            }
+            catch (InvalidCastException)
+            {
+                ThrowHelper.ThrowArgumentException(ExceptionResource.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 Int32)
+                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;
         }
 
         /**
@@ -591,7 +989,7 @@ namespace Microsoft.Win32
          *
          * @return a string representing the key.
          */
-        public override string ToString()
+        public override String ToString()
         {
             EnsureNotDisposed();
             return keyName;
@@ -604,7 +1002,7 @@ namespace Microsoft.Win32
          * error, and depending on the error, insert a string into the message
          * gotten from the ResourceManager.
          */
-        internal void Win32Error(int errorCode, string str)
+        internal void Win32Error(int errorCode, String str)
         {
             switch (errorCode)
             {
@@ -613,6 +1011,27 @@ namespace Microsoft.Win32
                         throw new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_RegistryKeyGeneric_Key, str));
                     else
                         throw new UnauthorizedAccessException();
+
+                case Win32Native.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 Win32Native.ERROR_FILE_NOT_FOUND:
                     throw new IOException(SR.Arg_RegKeyNotFound, errorCode);
 
@@ -621,6 +1040,76 @@ namespace Microsoft.Win32
             }
         }
 
+        internal static String FixupName(String name)
+        {
+            BCLDebug.Assert(name != null, "[FixupName]name!=null");
+            if (name.IndexOf('\\') == -1)
+                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 static void FixupPath(StringBuilder path)
+        {
+            Contract.Requires(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;
+            }
+        }
+
+        private bool ContainsRegistryValue(string name)
+        {
+            int type = 0;
+            int datasize = 0;
+            int retval = Win32Native.RegQueryValueEx(hkey, name, null, ref type, (byte[])null, ref datasize);
+            return retval == 0;
+        }
+
         private void EnsureNotDisposed()
         {
             if (hkey == null)
@@ -638,8 +1127,41 @@ namespace Microsoft.Win32
             }
         }
 
+        private static int GetRegistryKeyAccess(bool isWritable)
+        {
+            int winAccess;
+            if (!isWritable)
+            {
+                winAccess = Win32Native.KEY_READ;
+            }
+            else
+            {
+                winAccess = Win32Native.KEY_READ | Win32Native.KEY_WRITE;
+            }
+
+            return winAccess;
+        }
+
+        private RegistryKeyPermissionCheck GetSubKeyPermissonCheck(bool subkeyWritable)
+        {
+            if (checkMode == RegistryKeyPermissionCheck.Default)
+            {
+                return checkMode;
+            }
+
+            if (subkeyWritable)
+            {
+                return RegistryKeyPermissionCheck.ReadWriteSubTree;
+            }
+            else
+            {
+                return RegistryKeyPermissionCheck.ReadSubTree;
+            }
+        }
+
         static private void ValidateKeyName(string name)
         {
+            Contract.Ensures(name != null);
             if (name == null)
             {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.name);
@@ -660,9 +1182,33 @@ namespace Microsoft.Win32
                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegKeyStrLenBug);
         }
 
+        static private void ValidateKeyView(RegistryView view)
+        {
+            if (view != RegistryView.Default && view != RegistryView.Registry32 && view != RegistryView.Registry64)
+            {
+                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidRegistryViewCheck, ExceptionArgument.view);
+            }
+        }
+
         // Win32 constants for error handling
         private const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
         private const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
         private const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000;
     }
+
+    [Flags]
+    internal enum RegistryValueOptions
+    {
+        None = 0,
+        DoNotExpandEnvironmentNames = 1
+    }
+
+    // the name for this API is meant to mimic FileMode, which has similar values
+
+    internal enum RegistryKeyPermissionCheck
+    {
+        Default = 0,
+        ReadSubTree = 1,
+        ReadWriteSubTree = 2
+    }
 }
index 90c880b..6e2a4f3 100644 (file)
@@ -2,6 +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.
 
+
 namespace Microsoft.Win32
 {
     internal enum RegistryValueKind
@@ -12,11 +13,8 @@ namespace Microsoft.Win32
         DWord = Win32Native.REG_DWORD,
         MultiString = Win32Native.REG_MULTI_SZ,
         QWord = Win32Native.REG_QWORD,
-        Unknown = 0,
-
-        // REG_NONE is defined as zero but BCL, mistakingly overrode this value.
-        // Now instead of using Win32Native.REG_NONE we use "-1" and play games internally.
-        None = unchecked((int)0xFFFFFFFF),
-    }
+        Unknown = 0,                          // REG_NONE is defined as zero but BCL
+        None = unchecked((int)0xFFFFFFFF), //  mistakingly overrode this value.  
+    }   // Now instead of using Win32Native.REG_NONE we use "-1" and play games internally.
 }
 
diff --git a/src/coreclr/src/mscorlib/src/Microsoft/Win32/RegistryView.cs b/src/coreclr/src/mscorlib/src/Microsoft/Win32/RegistryView.cs
new file mode 100644 (file)
index 0000000..e415865
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+//
+//
+//
+// Implements Microsoft.Win32.RegistryView
+//
+// ======================================================================================
+
+using System;
+
+namespace Microsoft.Win32
+{
+    internal enum RegistryView
+    {
+        Default = 0,                           // 0x0000 operate on the default registry view
+        Registry64 = Win32Native.KEY_WOW64_64KEY, // 0x0100 operate on the 64-bit registry view
+        Registry32 = Win32Native.KEY_WOW64_32KEY, // 0x0200 operate on the 32-bit registry view
+    };
+}
index 1215000..64dbb2c 100644 (file)
@@ -2,9 +2,19 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+//
+//
+//
+// Implements Microsoft.Win32.SafeHandles.SafeRegistryHandle
+//
+// ======================================================================================
+
 using System;
 using System.Security;
 using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.Versioning;
 
 namespace Microsoft.Win32.SafeHandles
 {
index b9070ae..dddbdc2 100644 (file)
@@ -820,7 +820,7 @@ namespace System
                     }
                     else
                     {
-                        environmentKey.SetStringValue(variable, value);
+                        environmentKey.SetValue(variable, value);
                     }
                 }
             }
index 4ba95c8..869b809 100644 (file)
@@ -42,41 +42,54 @@ namespace System.Globalization
             int hijriAdvance = 0;
             Microsoft.Win32.RegistryKey key = null;
 
-            using (key = Registry.CurrentUser.OpenSubKey(InternationalRegKey, writable: false))
+            try
             {
-                if (key == null)
-                    return 0;
+                // Open in read-only mode.
+                // Use InternalOpenSubKey so that we avoid the security check.
+                key = RegistryKey.GetBaseKey(RegistryKey.HKEY_CURRENT_USER).OpenSubKey(InternationalRegKey, false);
+            }
+            //If this fails for any reason, we'll just return 0.
+            catch (ObjectDisposedException) { return 0; }
+            catch (ArgumentException) { return 0; }
 
-                Object value = key.GetValue(HijriAdvanceRegKeyEntry);
-                if (value == null)
-                {
-                    return (0);
-                }
-                String str = value.ToString();
-                if (String.Compare(str, 0, HijriAdvanceRegKeyEntry, 0, HijriAdvanceRegKeyEntry.Length, StringComparison.OrdinalIgnoreCase) == 0)
+            if (key != null)
+            {
+                try
                 {
-                    if (str.Length == HijriAdvanceRegKeyEntry.Length)
-                        hijriAdvance = -1;
-                    else
+                    Object value = key.InternalGetValue(HijriAdvanceRegKeyEntry, null, false, false);
+                    if (value == null)
                     {
-                        str = str.Substring(HijriAdvanceRegKeyEntry.Length);
-                        try
+                        return (0);
+                    }
+                    String str = value.ToString();
+                    if (String.Compare(str, 0, HijriAdvanceRegKeyEntry, 0, HijriAdvanceRegKeyEntry.Length, StringComparison.OrdinalIgnoreCase) == 0)
+                    {
+                        if (str.Length == HijriAdvanceRegKeyEntry.Length)
+                            hijriAdvance = -1;
+                        else
                         {
-                            int advance = Int32.Parse(str.ToString(), CultureInfo.InvariantCulture);
-                            if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri))
+                            str = str.Substring(HijriAdvanceRegKeyEntry.Length);
+                            try
                             {
-                                hijriAdvance = advance;
+                                int advance = Int32.Parse(str.ToString(), CultureInfo.InvariantCulture);
+                                if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri))
+                                {
+                                    hijriAdvance = advance;
+                                }
                             }
+                            // If we got garbage from registry just ignore it.
+                            // hijriAdvance = 0 because of declaraction assignment up above.
+                            catch (ArgumentException) { }
+                            catch (FormatException) { }
+                            catch (OverflowException) { }
                         }
-                        // If we got garbage from registry just ignore it.
-                        // hijriAdvance = 0 because of declaraction assignment up above.
-                        catch (ArgumentException) { }
-                        catch (FormatException) { }
-                        catch (OverflowException) { }
                     }
                 }
+                finally
+                {
+                    key.Close();
+                }
             }
-
             return (hijriAdvance);
         }
     }
index fe8b1b5..a83c4fa 100644 (file)
@@ -36,30 +36,30 @@ namespace System.Globalization
 
             try
             {
-                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(c_japaneseErasHive, writable: false))
+                // Need to access registry
+                RegistryKey key = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey(c_japaneseErasHive, false);
+
+                // Abort if we didn't find anything
+                if (key == null) return null;
+
+                // Look up the values in our reg key
+                String[] valueNames = key.GetValueNames();
+                if (valueNames != null && valueNames.Length > 0)
                 {
-                    // Abort if we didn't find anything
-                    if (key == null) return null;
+                    registryEraRanges = new EraInfo[valueNames.Length];
 
-                    // Look up the values in our reg key
-                    String[] valueNames = key.GetValueNames();
-                    if (valueNames != null && valueNames.Length > 0)
+                    // Loop through the registry and read in all the values
+                    for (int i = 0; i < valueNames.Length; i++)
                     {
-                        registryEraRanges = new EraInfo[valueNames.Length];
-
-                        // Loop through the registry and read in all the values
-                        for (int i = 0; i < valueNames.Length; i++)
-                        {
-                            // See if the era is a valid date
-                            EraInfo era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i]).ToString());
+                        // See if the era is a valid date
+                        EraInfo era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i]).ToString());
 
-                            // continue if not valid
-                            if (era == null) continue;
+                        // continue if not valid
+                        if (era == null) continue;
 
-                            // Remember we found one.
-                            registryEraRanges[iFoundEras] = era;
-                            iFoundEras++;
-                        }
+                        // Remember we found one.
+                        registryEraRanges[iFoundEras] = era;
+                        iFoundEras++;
                     }
                 }
             }
index b6585bd..f359a2a 100644 (file)
@@ -576,8 +576,8 @@ namespace System
                     // read LastEntry   {(yearN, 1, 1) - MaxValue       }
 
                     // read the FirstEntry and LastEntry key values (ex: "1980", "2038")
-                    int first = (int)dynamicKey.GetValue(FirstEntryValue, -1);
-                    int last = (int)dynamicKey.GetValue(LastEntryValue, -1);
+                    int first = (int)dynamicKey.GetValue(FirstEntryValue, -1, RegistryValueOptions.None);
+                    int last = (int)dynamicKey.GetValue(LastEntryValue, -1, RegistryValueOptions.None);
 
                     if (first == -1 || last == -1 || first > last)
                     {
@@ -587,7 +587,7 @@ namespace System
 
                     // read the first year entry
                     Win32Native.RegistryTimeZoneInformation dtzi;
-                    byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture)) as byte[];
+                    byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
                     if (regValue == null || regValue.Length != RegByteLength)
                     {
                         rules = null;
@@ -620,7 +620,7 @@ namespace System
                     // read the middle year entries
                     for (int i = first + 1; i < last; i++)
                     {
-                        regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture)) as byte[];
+                        regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
                         if (regValue == null || regValue.Length != RegByteLength)
                         {
                             rules = null;
@@ -640,7 +640,7 @@ namespace System
                     }
 
                     // read the last year entry
-                    regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture)) as byte[];
+                    regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
                     dtzi = new Win32Native.RegistryTimeZoneInformation(regValue);
                     if (regValue == null || regValue.Length != RegByteLength)
                     {
@@ -719,7 +719,7 @@ namespace System
                 }
 
                 Win32Native.RegistryTimeZoneInformation registryTimeZoneInfo;
-                byte[] regValue = key.GetValue(TimeZoneInfoValue) as byte[];
+                byte[] regValue = key.GetValue(TimeZoneInfoValue, null, RegistryValueOptions.None) as byte[];
                 if (regValue == null || regValue.Length != RegByteLength) return false;
                 registryTimeZoneInfo = new Win32Native.RegistryTimeZoneInformation(regValue);
 
@@ -756,7 +756,7 @@ namespace System
                 //
                 if (result)
                 {
-                    string registryStandardName = key.GetValue(StandardValue, string.Empty) as string;
+                    string registryStandardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string;
                     result = string.Equals(registryStandardName, timeZone.StandardName, StringComparison.Ordinal);
                 }
                 return result;
@@ -884,9 +884,9 @@ namespace System
             daylightName = string.Empty;
 
             // read the MUI_ registry keys
-            string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty) as string;
-            string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty) as string;
-            string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty) as string;
+            string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty, RegistryValueOptions.None) as string;
+            string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty, RegistryValueOptions.None) as string;
+            string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty, RegistryValueOptions.None) as string;
 
             // try to load the strings from the native resource DLL(s)
             if (!string.IsNullOrEmpty(displayNameMuiResource))
@@ -907,15 +907,15 @@ namespace System
             // fallback to using the standard registry keys
             if (string.IsNullOrEmpty(displayName))
             {
-                displayName = key.GetValue(DisplayValue, string.Empty) as string;
+                displayName = key.GetValue(DisplayValue, string.Empty, RegistryValueOptions.None) as string;
             }
             if (string.IsNullOrEmpty(standardName))
             {
-                standardName = key.GetValue(StandardValue, string.Empty) as string;
+                standardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string;
             }
             if (string.IsNullOrEmpty(daylightName))
             {
-                daylightName = key.GetValue(DaylightValue, string.Empty) as string;
+                daylightName = key.GetValue(DaylightValue, string.Empty, RegistryValueOptions.None) as string;
             }
 
             return true;
@@ -964,7 +964,7 @@ namespace System
                 }
 
                 Win32Native.RegistryTimeZoneInformation defaultTimeZoneInformation;
-                byte[] regValue = key.GetValue(TimeZoneInfoValue) as byte[];
+                byte[] regValue = key.GetValue(TimeZoneInfoValue, null, RegistryValueOptions.None) as byte[];
                 if (regValue == null || regValue.Length != RegByteLength)
                 {
                     // the registry value could not be cast to a byte array