RegistryKey.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / Microsoft / Win32 / RegistryKey.cs / 1305376 / RegistryKey.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

/* 
  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
  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 hack.  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.

*/ 

 
namespace Microsoft.Win32 { 

    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Security;
#if !FEATURE_PAL && FEATURE_MACL 
    using System.Security.AccessControl;
#endif 
    using System.Security.Permissions; 
    using System.Text;
    using System.Threading; 
    using System.IO;
    using System.Runtime.Remoting;
    using System.Runtime.InteropServices;
    using Microsoft.Win32.SafeHandles; 
    using System.Runtime.Versioning;
    using System.Globalization; 
    using System.Diagnostics.Contracts; 

#if !FEATURE_PAL 

    /**
     * Registry hive values.  Useful only for GetRemoteBaseKey
     */ 
    [Serializable]
[System.Runtime.InteropServices.ComVisible(true)] 
    public 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),
        DynData = unchecked((int)0x80000006), 
    } 

    /** 
     * 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) 
     */ 
#if FEATURE_REMOTING
    [ComVisible(true)] 
    public sealed class RegistryKey : MarshalByRefObject, IDisposable
#if false
    {}
#endif 
#else
    [ComVisible(true)] 
    public sealed class RegistryKey : IDisposable 
#endif
    { 

        // 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));
        internal static readonly IntPtr HKEY_DYN_DATA             = new IntPtr(unchecked((int)0x80000006)); 

        // 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".
        // 
        private const int STATE_SYSTEMKEY    = 0x0002;

        // Access
        // 
        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", 
                "HKEY_DYN_DATA"
                };

        // 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; 

        [System.Security.SecurityCritical /*auto-generated*/]
        private SafeRegistryHandle hkey = null;
        private int state = 0; 
        private String keyName;
        private bool remoteKey = false; 
        private RegistryKeyPermissionCheck checkMode; 
        private 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. 
         *
         * This key is bound to hkey, if writable is false then no write operations 
         * will be allowed. 
         */
        [System.Security.SecurityCritical]  // auto-generated 
        private RegistryKey(SafeRegistryHandle  hkey, bool writable, RegistryView view)
            : this(hkey, writable, false, false, false, view) {
        }
 

        /** 
         * Creates a RegistryKey. 
         *
         * This key is bound to hkey, if writable is false 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. 
         */
        [System.Security.SecurityCritical]  // auto-generated 
        private RegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey, bool remoteKey, bool isPerfData, RegistryView view) { 
            this.hkey = hkey;
            this.keyName = ""; 
            this.remoteKey = remoteKey;
            this.regView = view;
            if (systemkey) {
                this.state |= STATE_SYSTEMKEY; 
            }
            if (writable) { 
                this.state |= STATE_WRITEACCESS; 
            }
            if (isPerfData) 
                this.state |= STATE_PERF_DATA;
            ValidateKeyView(view);
        }
 
        /**
         * Closes this key, flushes it to disk if the contents have been modified. 
         */ 
        public void Close() {
            Dispose(true); 
        }

        [System.Security.SecuritySafeCritical]  // auto-generated
        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 ---- 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 of ---- 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); 
                }
            } 
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated 
        public void Flush() {
            if (hkey != null) {
                 if (IsDirty()) {
                     Win32Native.RegFlushKey(hkey); 
                }
            } 
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated 
#if FEATURE_CORECLR
        void IDisposable.Dispose()
#if false // ugly hack to fix syntax for TrimSrc parser, which ignores #if directives
        { 
        }
#endif 
#else 
        public void Dispose()
#endif 
        {
            Dispose(true);
        }
 
        /**
         * Creates a new subkey, or opens an existing one. 
         * 
         * @param subkey Name or path to subkey to create or open.
         * 
         * @return the subkey, or null if the operation failed.
         */
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public RegistryKey CreateSubKey(String subkey) {
            return CreateSubKey(subkey, checkMode); 
        } 

        [ComVisible(false)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public RegistryKey CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck)
        { 
            return CreateSubKeyInternal(subkey, permissionCheck, null, RegistryOptions.None);
        } 
 
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public RegistryKey CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options)
        {
            return CreateSubKeyInternal(subkey, permissionCheck, null, options); 
        }
 
 
#if !FEATURE_PAL && FEATURE_MACL
        [ComVisible(false)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public unsafe RegistryKey CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck,  RegistrySecurity registrySecurity)
        { 
            return CreateSubKeyInternal(subkey, permissionCheck, registrySecurity, RegistryOptions.None);
        } 
 
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public unsafe RegistryKey CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck,  RegistryOptions registryOptions, RegistrySecurity registrySecurity)
        {
            return CreateSubKeyInternal(subkey, permissionCheck, registrySecurity, registryOptions); 
        }
#endif 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private unsafe RegistryKey CreateSubKeyInternal(String subkey, RegistryKeyPermissionCheck permissionCheck, object registrySecurityObj, RegistryOptions registryOptions)
        { 
            ValidateKeyOptions(registryOptions);
            ValidateKeyName(subkey); 
            ValidateKeyMode(permissionCheck); 
            EnsureWriteable();
            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash 

            // only keys opened under read mode is not writable
            if (!remoteKey) {
                RegistryKey key = InternalOpenSubKey(subkey, (permissionCheck != RegistryKeyPermissionCheck.ReadSubTree)); 
                if (key != null)  { // Key already exits
                    CheckPermission(RegistryInternalCheck.CheckSubKeyWritePermission, subkey, false, RegistryKeyPermissionCheck.Default); 
                    CheckPermission(RegistryInternalCheck.CheckSubTreePermission, subkey, false, permissionCheck); 
                    key.checkMode = permissionCheck;
                    return key; 
                }
            }

            CheckPermission(RegistryInternalCheck.CheckSubKeyCreatePermission, subkey, false, RegistryKeyPermissionCheck.Default); 

            Win32Native.SECURITY_ATTRIBUTES secAttrs = null; 
#if !FEATURE_PAL && FEATURE_MACL 
            RegistrySecurity registrySecurity = (RegistrySecurity)registrySecurityObj;
            // For ACL's, get the security descriptor from the RegistrySecurity. 
            if (registrySecurity != null) {
                secAttrs = new Win32Native.SECURITY_ATTRIBUTES();
                secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
 
                byte[] sd = registrySecurity.GetSecurityDescriptorBinaryForm();
                // We allocate memory on the stack to improve the speed. 
                // So this part of code can't be refactored into a method. 
                byte* pSecDescriptor = stackalloc byte[sd.Length];
                Buffer.memcpy(sd, 0, pSecDescriptor, 0, sd.Length); 
                secAttrs.pSecurityDescriptor = pSecDescriptor;
            }
#endif
            int disposition = 0; 

            // By default, the new key will be writable. 
            SafeRegistryHandle result = null; 
            int ret = Win32Native.RegCreateKeyEx(hkey,
                subkey, 
                0,
                null,
                (int)registryOptions /* specifies if the key is volatile */,
                GetRegistryKeyAccess(permissionCheck != RegistryKeyPermissionCheck.ReadSubTree, regView), 
                secAttrs,
                out result, 
                out disposition); 

            if (ret == 0 && !result.IsInvalid) { 
                RegistryKey key = new RegistryKey(result, (permissionCheck != RegistryKeyPermissionCheck.ReadSubTree), false, remoteKey, false, regView);
                CheckPermission(RegistryInternalCheck.CheckSubTreePermission, subkey, false, permissionCheck);
                key.checkMode = permissionCheck;
 
                if (subkey.Length == 0)
                    key.keyName = keyName; 
                else 
                    key.keyName = keyName + "\\" + subkey;
                return key; 
            }
            else if (ret != 0) // syscall failed, ret is an error code.
                Win32Error(ret, keyName + "\\" + subkey);  // Access denied?
 
            BCLDebug.Assert(false, "Unexpected code path in RegistryKey::CreateSubKey");
            return null; 
        } 

        /** 
         * Deletes the specified subkey. Will throw an exception if the subkey has
         * subkeys. To delete a tree of subkeys use, DeleteSubKeyTree.
         *
         * @param subkey SubKey to delete. 
         *
         * @exception InvalidOperationException thrown if the subkey has child subkeys. 
         */ 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void DeleteSubKey(String subkey) {
            DeleteSubKey(subkey, true);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)] 
        public void DeleteSubKey(String subkey, bool throwOnMissingSubKey) {
            ValidateKeyName(subkey); 
            EnsureWriteable();
            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash
            CheckPermission(RegistryInternalCheck.CheckSubKeyWritePermission, subkey, false, RegistryKeyPermissionCheck.Default);
 
            // Open the key we are deleting and check for children. Be sure to
            // explicitly call close to avoid keeping an extra HKEY open. 
            // 
            RegistryKey key = InternalOpenSubKey(subkey,false);
            if (key != null) { 
                try {
                    if (key.InternalSubKeyCount() > 0) {
                        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_RegRemoveSubKey);
                    } 
                }
                finally { 
                    key.Close(); 
                }
 
                int ret;

                try {
                    ret = Win32Native.RegDeleteKeyEx(hkey, subkey, (int)regView, 0); 
                }
                catch (EntryPointNotFoundException) { 
                    // 
                    ret = Win32Native.RegDeleteKey(hkey, subkey);
                } 

                if (ret!=0) {
                    if (ret == Win32Native.ERROR_FILE_NOT_FOUND) {
                        if (throwOnMissingSubKey) 
                            ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegSubKeyAbsent);
                    } 
                    else 
                        Win32Error(ret, null);
                } 
            }
            else { // there is no key which also means there is no subkey
                if (throwOnMissingSubKey)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegSubKeyAbsent); 
            }
        } 
 
        /**
         * Recursively deletes a subkey and any child subkeys. 
         *
         * @param subkey SubKey to delete.
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void DeleteSubKeyTree(String subkey) { 
            DeleteSubKeyTree(subkey, true /*throwOnMissingSubKey*/);
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public void DeleteSubKeyTree(String subkey, Boolean throwOnMissingSubKey) { 
            ValidateKeyName(subkey); 

            // Security concern: Deleting a hive's "" subkey would delete all 
            // of that hive's contents.  Don't allow "".
            if (subkey.Length==0 && IsSystemKey()) {
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegKeyDelHive);
            } 

            EnsureWriteable(); 
 
            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash
            CheckPermission(RegistryInternalCheck.CheckSubTreeWritePermission, subkey, false, RegistryKeyPermissionCheck.Default); 

            RegistryKey key = InternalOpenSubKey(subkey, true);
            if (key != null) {
                try { 
                    if (key.InternalSubKeyCount() > 0) {
                        String[] keys = key.InternalGetSubKeyNames(); 
 
                        for (int i=0; i 0) { 
                        String[] keys = key.InternalGetSubKeyNames(); 

                        for (int i=0; i= 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,false, isPerf, view);
            key.checkMode = RegistryKeyPermissionCheck.Default;
            key.keyName = hkeyNames[index];
            return key; 
        }
 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        [ComVisible(false)]
        public static RegistryKey OpenBaseKey(RegistryHive hKey, RegistryView view) {
            ValidateKeyView(view); 
            CheckUnmanagedCodePermission();
            return GetBaseKey((IntPtr)((int)hKey), view); 
        } 

        /** 
         * Retrieves a new RegistryKey that represents the requested key on a foreign
         * machine.  Valid values for hKey are members of the RegistryHive enum, or
         * Win32 integers such as:
         * 
         * 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. 
         * @param machineName the machine to connect to
         * 
         * @return the RegistryKey requested. 
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey, String machineName) {
            return OpenRemoteBaseKey(hKey, machineName, RegistryView.Default); 
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey, String machineName, RegistryView view) {
            if (machineName==null)
                throw new ArgumentNullException("machineName"); 
            int index = (int)hKey & 0x0FFFFFFF;
            if (index < 0 || index >= hkeyNames.Length || ((int)hKey & 0xFFFFFFF0) != 0x80000000) { 
                throw new ArgumentException(Environment.GetResourceString("Arg_RegKeyOutOfRange")); 
            }
            ValidateKeyView(view); 

            CheckUnmanagedCodePermission();
            // connect to the specified remote registry
            SafeRegistryHandle foreignHKey = null; 
            int ret = Win32Native.RegConnectRegistry(machineName, new SafeRegistryHandle(new IntPtr((int)hKey), false), out foreignHKey);
 
            if (ret == Win32Native.ERROR_DLL_INIT_FAILED) 
                // return value indicates an error occurred
                throw new ArgumentException(Environment.GetResourceString("Arg_DllInitFailure")); 

            if (ret != 0)
                Win32ErrorStatic(ret, null);
 
            if (foreignHKey.IsInvalid)
                // return value indicates an error occurred 
                throw new ArgumentException(Environment.GetResourceString("Arg_RegKeyNoRemoteConnect", machineName)); 

            RegistryKey key = new RegistryKey(foreignHKey, true, false, true, ((IntPtr) hKey) == HKEY_PERFORMANCE_DATA, view); 
            key.checkMode = RegistryKeyPermissionCheck.Default;
            key.keyName = hkeyNames[index];
            return key;
        } 

        /** 
         * Retrieves a subkey. If readonly is true, then the subkey is opened with 
         * read-only access.
         * 
         * @param name Name or path of subkey to open.
         * @param readonly Set to true if you only need readonly access.
         *
         * @return the Subkey requested, or null if the operation failed. 
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public RegistryKey OpenSubKey(string name, bool writable ) { 
            ValidateKeyName(name);
            EnsureNotDisposed();
            name = FixupName(name); // Fixup multiple slashes to a single slash
 
            CheckPermission(RegistryInternalCheck.CheckOpenSubKeyWithWritablePermission, name, writable, RegistryKeyPermissionCheck.Default);
            SafeRegistryHandle result = null; 
            int ret = Win32Native.RegOpenKeyEx(hkey, name, 0, GetRegistryKeyAccess(writable, 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 == Win32Native.ERROR_ACCESS_DENIED || ret == Win32Native.ERROR_BAD_IMPERSONATION_LEVEL) {
                // We need to throw SecurityException here for compatibility reasons, 
                // although UnauthorizedAccessException will make more sense.
                ThrowHelper.ThrowSecurityException(ExceptionResource.Security_RegistryPermission);
            }
 
            return null;
        } 
 
#if FEATURE_MACL
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public RegistryKey OpenSubKey(String name, RegistryKeyPermissionCheck permissionCheck) {
            ValidateKeyMode(permissionCheck); 
            return InternalOpenSubKey(name, permissionCheck, GetRegistryKeyAccess(permissionCheck, regView)); 
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public RegistryKey OpenSubKey(String name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights) {
            return InternalOpenSubKey(name, permissionCheck, (int)rights); 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private RegistryKey InternalOpenSubKey(String name, RegistryKeyPermissionCheck permissionCheck, int rights) {
            ValidateKeyName(name); 
            ValidateKeyMode(permissionCheck);
 
            ValidateKeyRights(rights); 

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

            CheckPermission(RegistryInternalCheck.CheckOpenSubKeyPermission, name, false, permissionCheck);
            CheckPermission(RegistryInternalCheck.CheckSubTreePermission, name, false, permissionCheck); 
            SafeRegistryHandle result = null;
            int ret = Win32Native.RegOpenKeyEx(hkey, name, 0, (rights | (int)regView), out result); 
            if (ret == 0 && !result.IsInvalid) { 
                RegistryKey key = new RegistryKey(result, (permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree), false, remoteKey, false, regView);
                key.keyName = keyName + "\\" + name; 
                key.checkMode = permissionCheck;
                return key;
            }
 
            // Return null if we didn't find the key.
            if (ret == Win32Native.ERROR_ACCESS_DENIED || ret == Win32Native.ERROR_BAD_IMPERSONATION_LEVEL) { 
                // We need to throw SecurityException here for compatiblity reason, 
                // although UnauthorizedAccessException will make more sense.
                ThrowHelper.ThrowSecurityException(ExceptionResource.Security_RegistryPermission); 
            }

            return null;
        } 
#endif
 
        // 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
        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        internal RegistryKey InternalOpenSubKey(String name, bool writable) {
            ValidateKeyName(name); 
            EnsureNotDisposed();
 
            SafeRegistryHandle result = null; 
            int ret = Win32Native.RegOpenKeyEx(hkey, name, 0, GetRegistryKeyAccess(writable, 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 null if the operation failed.
         */ 
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public RegistryKey OpenSubKey(String name) { 
            return OpenSubKey(name, false);
        }

        /** 
         * Retrieves the count of subkeys.
         * 
         * @return a count of subkeys. 
         */
        public int SubKeyCount { 
            [System.Security.SecuritySafeCritical]  // auto-generated
            get {
                CheckPermission(RegistryInternalCheck.CheckKeyReadPermission, null, false, RegistryKeyPermissionCheck.Default);
                return InternalSubKeyCount(); 
            }
        } 
 
        [ComVisible(false)]
        public RegistryView View { 
            [System.Security.SecuritySafeCritical]
            get {
                EnsureNotDisposed();
                return regView; 
            }
        } 
 
        [ComVisible(false)]
        public SafeRegistryHandle Handle { 
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            [System.Security.SecurityCritical]
            [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
            get {
                EnsureNotDisposed(); 
                int ret = Win32Native.ERROR_INVALID_HANDLE; 
                if (IsSystemKey()) {
                    IntPtr baseKey = (IntPtr)0; 
                    switch (keyName) {
                        case "HKEY_CLASSES_ROOT":
                            baseKey = HKEY_CLASSES_ROOT;
                            break; 
                        case "HKEY_CURRENT_USER":
                            baseKey = HKEY_CURRENT_USER; 
                            break; 
                        case "HKEY_LOCAL_MACHINE":
                            baseKey = HKEY_LOCAL_MACHINE; 
                            break;
                        case "HKEY_USERS":
                            baseKey = HKEY_USERS;
                            break; 
                        case "HKEY_PERFORMANCE_DATA":
                            baseKey = HKEY_PERFORMANCE_DATA; 
                            break; 
                        case "HKEY_CURRENT_CONFIG":
                            baseKey = HKEY_CURRENT_CONFIG; 
                            break;
                        case "HKEY_DYN_DATA":
                            baseKey = HKEY_DYN_DATA;
                            break; 
                        default:
                            Win32Error(ret, null); 
                            break; 
                    }
                    // open the base key so that RegistryKey.Handle will return a valid handle 
                    SafeRegistryHandle result;
                    ret = Win32Native.RegOpenKeyEx(baseKey, null, 0, GetRegistryKeyAccess(IsWritable(), regView), out result);
                    if (ret == 0 && !result.IsInvalid) {
                        return result; 
                    }
                    else { 
                        Win32Error(ret, null); 
                    }
                } 
                else {
                    return hkey;
                }
                throw new IOException(Win32Native.GetMessage(ret), ret); 
            }
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        [System.Security.SecurityCritical]
        [ComVisible(false)]
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public static RegistryKey FromHandle(SafeRegistryHandle handle) { 
            return FromHandle(handle, RegistryView.Default);
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        [System.Security.SecurityCritical]
        [ComVisible(false)]
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public static RegistryKey FromHandle(SafeRegistryHandle handle, RegistryView view) { 
            if (handle == null) throw new ArgumentNullException("handle");
            ValidateKeyView(view); 
 
            return new RegistryKey(handle, true /* isWritable */, view);
        } 

        [System.Security.SecurityCritical]  // auto-generated
        internal int InternalSubKeyCount() {
                EnsureNotDisposed(); 

                int subkeys = 0; 
                int junk = 0; 
                int ret = Win32Native.RegQueryInfoKey(hkey,
                                          null, 
                                          null,
                                          Win32Native.NULL,
                                          ref subkeys,  // subkeys
                                          null, 
                                          null,
                                          ref junk,     // values 
                                          null, 
                                          null,
                                          null, 
                                          null);

                if (ret != 0)
                    Win32Error(ret, null); 
                return subkeys;
        } 
 
        /**
         * Retrieves an array of strings containing all the subkey names. 
         *
         * @return all subkey names.
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        public String[] GetSubKeyNames() {
            CheckPermission(RegistryInternalCheck.CheckKeyReadPermission, null, false, RegistryKeyPermissionCheck.Default); 
            return InternalGetSubKeyNames(); 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal String[] InternalGetSubKeyNames() {
            EnsureNotDisposed();
            int subkeys = InternalSubKeyCount(); 
            String[] names = new String[subkeys];  // Returns 0-length array if empty.
 
            if (subkeys > 0) { 
                StringBuilder name = new StringBuilder(MaxKeyLength+1);
                int namelen; 

                for (int i=0; i 0) { 
                StringBuilder name = new StringBuilder(MaxValueLength+1); 
                int namelen;
 
                for (int i=0; inull is returned if the value
         * doesn't exist. 
         *
         * Note that name 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. 
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        public Object GetValue(String name) {
            CheckPermission(RegistryInternalCheck.CheckValueReadPermission, name, false, RegistryKeyPermissionCheck.Default);
            return InternalGetValue(name, null, false, true);
        } 

        /** 
         * Retrieves the specified value. defaultValue is returned if the value doesn't exist. 
         *
         * Note that name 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.  On
         * Win95, the default value is always an empty key of type REG_SZ. 
         * Win98 supports default values of any type, but defaults to REG_SZ.
         * 
         * @param name Name of value to retrieve. 
         * @param defaultValue Value to return if name doesn't exist.
         * 
         * @return the data associated with the value.
         */
        [System.Security.SecuritySafeCritical]  // auto-generated
        public Object GetValue(String name, Object defaultValue) { 
            CheckPermission(RegistryInternalCheck.CheckValueReadPermission, name, false, RegistryKeyPermissionCheck.Default);
            return InternalGetValue(name, defaultValue, false, true); 
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ComVisible(false)]
        public Object GetValue(String name, Object defaultValue, RegistryValueOptions options) {
            if( options < RegistryValueOptions.None || options > RegistryValueOptions.DoNotExpandEnvironmentNames) {
                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)options), "options"); 
            }
            bool doNotExpand = (options == RegistryValueOptions.DoNotExpandEnvironmentNames); 
            CheckPermission(RegistryInternalCheck.CheckValueReadPermission, name, false, RegistryKeyPermissionCheck.Default); 
            return InternalGetValue(name, defaultValue, doNotExpand, true);
        } 

        [System.Security.SecurityCritical]  // auto-generated
        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 = Win32Native.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 (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 
                BCLDebug.Assert(false, "[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize"); 
                datasize = 0;
            } 


            switch (type) {
            case Win32Native.REG_NONE: 
            case Win32Native.REG_DWORD_BIG_ENDIAN:
            case Win32Native.REG_BINARY: { 
                                 byte[] blob = new byte[datasize]; 
                                 ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
                                 data = blob; 
                             }
                             break;
            case Win32Native.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 Win32Native.REG_BINARY; 
                                 }
                                 long blob = 0; 
                                 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);
 
                                 data = blob;
                             } 
                             break; 
            case Win32Native.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 Win32Native.REG_QWORD;
                                 } 
                                 int blob = 0;
                                 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);
 
                                 data = blob;
                             }
                             break;
 
            case Win32Native.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(Environment.GetResourceString("Arg_RegGetOverflowBug"), e); 
                                     }
                                 } 
                                 char[] blob = new char[datasize/2]; 

                                 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);
                                 }
                                 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 Win32Native.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(Environment.GetResourceString("Arg_RegGetOverflowBug"), e);
                                     }
                                 } 
                                 char[] blob = new char[datasize/2];
 
                                 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);
                                 }
                                 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 Win32Native.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(Environment.GetResourceString("Arg_RegGetOverflowBug"), e);
                                     } 
                                 }
                                 char[] blob = new char[datasize/2]; 
 
                                 ret = Win32Native.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(Environment.GetResourceString("Arg_RegGetOverflowBug"), e);
                                     } 
                                     blob[blob.Length - 1] = (char)0;
                                 } 
 

                                 IList strings = new List(); 
                                 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) {
                                         BCLDebug.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 Win32Native.REG_LINK:
            default: 
                break; 
            }
 
            return data;
        }

 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)] 
        public RegistryValueKind GetValueKind(string name) { 
            CheckPermission(RegistryInternalCheck.CheckValueReadPermission, name, false, RegistryKeyPermissionCheck.Default);
            EnsureNotDisposed(); 

            int type = 0;
            int datasize = 0;
            int ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, (byte[])null, ref datasize); 
            if (ret != 0)
                Win32Error(ret, null); 
            if (type == Win32Native.REG_NONE) 
                return RegistryValueKind.None;
            else if (!Enum.IsDefined(typeof(RegistryValueKind), type)) 
                return RegistryValueKind.Unknown;
            else
                return (RegistryValueKind) type;
        } 

        /** 
         * Retrieves the current state of the dirty property. 
         *
         * A key is marked as dirty if any operation has occured that modifies the 
         * contents of the key.
         *
         * @return true if the key has been modified.
         */ 
        private bool IsDirty() {
            return (this.state & STATE_DIRTY) != 0; 
        } 

        private bool IsSystemKey() { 
            return (this.state & STATE_SYSTEMKEY) != 0;
        }

        private bool IsWritable() { 
            return (this.state & STATE_WRITEACCESS) != 0;
        } 
 
        private bool IsPerfDataKey() {
            return (this.state & STATE_PERF_DATA) != 0; 
        }

        public String Name {
            [System.Security.SecuritySafeCritical]  // auto-generated 
            get {
                EnsureNotDisposed(); 
                return keyName; 
            }
        } 

        private void SetDirty() {
            this.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); 
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ComVisible(false)]
        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(Environment.GetResourceString("Arg_RegValStrLenBug"));
            } 
 
            if (!Enum.IsDefined(typeof(RegistryValueKind), valueKind))
                throw new ArgumentException(Environment.GetResourceString("Arg_RegBadKeyKind"), "valueKind"); 

            EnsureWriteable();

            if (!remoteKey && ContainsRegistryValue(name)) { // Existing key 
                CheckPermission(RegistryInternalCheck.CheckValueWritePermission, name, false, RegistryKeyPermissionCheck.Default);
            } 
             else { // Creating a new value 
                CheckPermission(RegistryInternalCheck.CheckValueCreatePermission, name, false, RegistryKeyPermissionCheck.Default);
            } 

            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= 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;
            }
 
        }
 
        // 
        // Read/Write/Create SubKey Permission
        // 
        private void GetSubKeyReadPermission(string subkeyName, out RegistryPermissionAccess access, out string path) {
            access = RegistryPermissionAccess.Read;
            path   = keyName + "\\" + subkeyName + "\\.";
        } 
        private void GetSubKeyWritePermission(string subkeyName, out RegistryPermissionAccess access, out string path) {
            // If we want to open a subkey of a read-only key as writeable, we need to do the check. 
            access = RegistryPermissionAccess.Write; 
            path   = keyName + "\\" + subkeyName + "\\.";
        } 
        private void GetSubKeyCreatePermission(string subkeyName, out RegistryPermissionAccess access, out string path) {
            access = RegistryPermissionAccess.Create;
            path   = keyName + "\\" + subkeyName + "\\.";
        } 

        // 
        // Read/Write/ReadWrite SubTree Permission 
        //
        private void GetSubTreeReadPermission(string subkeyName, out RegistryPermissionAccess access, out string path) { 
            access = RegistryPermissionAccess.Read;
            path   = keyName + "\\" + subkeyName + "\\";
        }
        private void GetSubTreeWritePermission(string subkeyName, out RegistryPermissionAccess access, out string path) { 
            access = RegistryPermissionAccess.Write;
            path   = keyName + "\\" + subkeyName + "\\"; 
        } 
        private void GetSubTreeReadWritePermission(string subkeyName, out RegistryPermissionAccess access, out string path) {
            access = RegistryPermissionAccess.Write | RegistryPermissionAccess.Read; 
            path   = keyName + "\\" + subkeyName;
        }

        // 
        // Read/Write/Create Value Permission
        // 
        private void GetValueReadPermission(string valueName, out RegistryPermissionAccess access, out string path) { 
            access = RegistryPermissionAccess.Read;
            path   = keyName+"\\"+valueName; 
        }
        private void GetValueWritePermission(string valueName, out RegistryPermissionAccess access, out string path) {
            access = RegistryPermissionAccess.Write;
            path   = keyName+"\\"+valueName; 
        }
        private void GetValueCreatePermission(string valueName, out RegistryPermissionAccess access, out string path) { 
            access = RegistryPermissionAccess.Create; 
            path   = keyName+"\\"+valueName;
        } 

        // Read Key Permission
        private void GetKeyReadPermission(out RegistryPermissionAccess access, out string path) {
           access = RegistryPermissionAccess.Read; 
           path   = keyName + "\\.";
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        private void CheckPermission(RegistryInternalCheck check, string item, bool subKeyWritable, RegistryKeyPermissionCheck subKeyCheck) { 
            bool demand = false;
            RegistryPermissionAccess access = RegistryPermissionAccess.NoAccess;
            string path = null;
 
#if !FEATURE_CORECLR
            if (CodeAccessSecurityEngine.QuickCheckForAllDemands()) { 
                return; // full trust fast path 
            }
#endif // !FEATURE_CORECLR 

            switch (check) {
                //
                // Read/Write/Create SubKey Permission 
                //
                case RegistryInternalCheck.CheckSubKeyReadPermission: 
                    if (remoteKey) { 
                        CheckUnmanagedCodePermission();
                    } 
                    else {
                        BCLDebug.Assert(checkMode == RegistryKeyPermissionCheck.Default, "Should be called from a key opened under default mode only!");
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        demand = true;
                        GetSubKeyReadPermission(item, out access, out path); 
                    } 
                    break;
                case RegistryInternalCheck.CheckSubKeyWritePermission: 
                    if (remoteKey) {
                        CheckUnmanagedCodePermission();
                    }
                    else { 
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow creating sub key under read-only key!");
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)"); 
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            demand = true; 
                            GetSubKeyWritePermission(item, out access, out path);
                        }
                    }
                    break; 
                case RegistryInternalCheck.CheckSubKeyCreatePermission:
                    if (remoteKey) { 
                        CheckUnmanagedCodePermission(); 
                    }
                    else { 
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow creating sub key under read-only key!");
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)");
                        if( checkMode == RegistryKeyPermissionCheck.Default) { 
                            demand = true;
                            GetSubKeyCreatePermission(item, out access, out path); 
                        } 
                    }
                    break; 
                //
                // Read/Write/ReadWrite SubTree Permission
                //
                case RegistryInternalCheck.CheckSubTreeReadPermission: 
                    if (remoteKey) {
                        CheckUnmanagedCodePermission(); 
                    } 
                    else {
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)"); 
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)");
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            demand = true;
                            GetSubTreeReadPermission(item, out access, out path); 
                        }
                    } 
                    break; 
                case RegistryInternalCheck.CheckSubTreeWritePermission:
                    if (remoteKey) { 
                        CheckUnmanagedCodePermission();
                    }
                    else {
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow writing value to read-only key!"); 
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        if( checkMode == RegistryKeyPermissionCheck.Default) { 
                            demand = true;
                            GetSubTreeWritePermission(item, out access, out path); 
                        }
                    }
                    break;
                case RegistryInternalCheck.CheckSubTreeReadWritePermission: 
                    if (remoteKey) {
                        CheckUnmanagedCodePermission(); 
                    } 
                    else {
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)"); 
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)");
                        // If we want to open a subkey of a read-only key as writeable, we need to do the check.
                        demand = true;
                        GetSubTreeReadWritePermission(item, out access, out path); 
                    }
                    break; 
                // 
                // Read/Write/Create Value Permission
                // 
                case RegistryInternalCheck.CheckValueReadPermission:
                    ///*** no remoteKey check ***///
                    BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                    BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                    if( checkMode == RegistryKeyPermissionCheck.Default) {
                        // only need to check for default mode (dynamice check) 
                        demand = true; 
                        GetValueReadPermission(item, out access, out path);
                    } 
                    break;
                case RegistryInternalCheck.CheckValueWritePermission:
                    if (remoteKey) {
                        CheckUnmanagedCodePermission(); 
                    }
                    else { 
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow writing value to read-only key!"); 
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        // skip the security check if the key is opened under write mode
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            demand = true;
                            GetValueWritePermission(item, out access, out path); 
                        }
                    } 
                    break; 
                case RegistryInternalCheck.CheckValueCreatePermission:
                    if (remoteKey) { 
                        CheckUnmanagedCodePermission();
                    }
                    else {
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow creating value under read-only key!"); 
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        // skip the security check if the key is opened under write mode 
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            demand = true; 
                            GetValueCreatePermission(item, out access, out path);
                        }
                    }
                    break; 
                //
                // CheckKeyReadPermission 
                // 
                case RegistryInternalCheck.CheckKeyReadPermission:
                    ///*** no remoteKey check ***/// 
                    if( checkMode == RegistryKeyPermissionCheck.Default) {
                        BCLDebug.Assert(item == null, "CheckKeyReadPermission should never have a non-null item parameter!");
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 

                        // only need to check for default mode (dynamice check) 
                        demand = true; 
                        GetKeyReadPermission(out access, out path);
                    } 
                    break;
                //
                // CheckSubTreePermission
                // 
                case RegistryInternalCheck.CheckSubTreePermission:
                    BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)"); 
                    if( subKeyCheck == RegistryKeyPermissionCheck.ReadSubTree) { 
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            if( remoteKey) { 
                                CheckUnmanagedCodePermission();
                            }
                            else {
                                demand = true; 
                                GetSubTreeReadPermission(item, out access, out path);
                            } 
                        } 
                    }
                    else if(subKeyCheck == RegistryKeyPermissionCheck.ReadWriteSubTree) { 
                        if( checkMode != RegistryKeyPermissionCheck.ReadWriteSubTree) {
                            if( remoteKey) {
                                CheckUnmanagedCodePermission();
                            } 
                            else {
                                demand = true; 
                                GetSubTreeReadWritePermission(item, out access, out path); 
                            }
                        } 
                    }
                    break;

                // 
                // CheckOpenSubKeyWithWritablePermission uses the 'subKeyWritable' parameter
                // 
                case RegistryInternalCheck.CheckOpenSubKeyWithWritablePermission: 
                    BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)");
                    // If the parent key is not opened under default mode, we have access already. 
                    // If the parent key is opened under default mode, we need to check for permission.
                    if(checkMode == RegistryKeyPermissionCheck.Default) {
                        if( remoteKey) {
                            CheckUnmanagedCodePermission(); 
                        }
                        else { 
                            demand = true; 
                            GetSubKeyReadPermission(item, out access, out path);
                        } 
                        break;
                    }
                    if( subKeyWritable && (checkMode == RegistryKeyPermissionCheck.ReadSubTree)) {
                        if( remoteKey) { 
                            CheckUnmanagedCodePermission();
                        } 
                        else { 
                            demand = true;
                            GetSubTreeReadWritePermission(item, out access, out path); 
                        }
                        break;
                    }
                    break; 

                // 
                // CheckOpenSubKeyPermission uses the 'subKeyCheck' parameter 
                //
                case RegistryInternalCheck.CheckOpenSubKeyPermission: 
                    BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                    if(subKeyCheck == RegistryKeyPermissionCheck.Default) {
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            if(remoteKey) { 
                                CheckUnmanagedCodePermission();
                            } 
                            else { 
                                demand = true;
                                GetSubKeyReadPermission(item, out access, out path); 
                            }
                        }
                    }
                    break; 

                default: 
                    BCLDebug.Assert(false, "CheckPermission default switch case should never be hit!"); 
                    break;
            } 

            if (demand) {
                new RegistryPermission(access, path).Demand();
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        static private void  CheckUnmanagedCodePermission() {
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); 
        }

        [System.Security.SecurityCritical]  // auto-generated
        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;
        } 

        [System.Security.SecurityCritical]  // auto-generated
        private void EnsureNotDisposed(){
            if (hkey == null) { 
                ThrowHelper.ThrowObjectDisposedException(keyName, ExceptionResource.ObjectDisposed_RegKeyClosed);
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        private void EnsureWriteable() {
            EnsureNotDisposed();
            if (!IsWritable()) {
                ThrowHelper.ThrowUnauthorizedAccessException(ExceptionResource.UnauthorizedAccess_RegistryNoWrite); 
            }
        } 
 
        static int GetRegistryKeyAccess(bool isWritable, RegistryView view) {
            int winAccess; 
            if (!isWritable) {
                winAccess = Win32Native.KEY_READ;
            }
            else { 
                winAccess = Win32Native.KEY_READ | Win32Native.KEY_WRITE;
            } 
            winAccess = winAccess | (int)view; 
            return winAccess;
        } 

        static int GetRegistryKeyAccess(RegistryKeyPermissionCheck mode, RegistryView view) {
            int winAccess = 0;
            switch(mode) { 
                case RegistryKeyPermissionCheck.ReadSubTree:
                case RegistryKeyPermissionCheck.Default: 
                    winAccess =  Win32Native.KEY_READ; 
                    break;
 
                case RegistryKeyPermissionCheck.ReadWriteSubTree:
                    winAccess = Win32Native.KEY_READ| Win32Native.KEY_WRITE;
                    break;
 
               default:
                    BCLDebug.Assert(false, "unexpected code path"); 
                    break; 
            }
            winAccess = winAccess | (int)view; 
            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);
            }
 
            int nextSlash = name.IndexOf("\\", StringComparison.OrdinalIgnoreCase);
            int current = 0; 
            while (nextSlash != -1) { 
                if ((nextSlash - current) > MaxKeyLength)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegKeyStrLenBug); 

                current = nextSlash + 1;
                nextSlash = name.IndexOf("\\", current, StringComparison.OrdinalIgnoreCase);
            } 

            if ((name.Length - current) > MaxKeyLength) 
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegKeyStrLenBug); 

        } 

        static private void ValidateKeyMode(RegistryKeyPermissionCheck mode) {
            if( mode < RegistryKeyPermissionCheck.Default || mode > RegistryKeyPermissionCheck.ReadWriteSubTree) {
                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidRegistryKeyPermissionCheck, ExceptionArgument.mode); 
            }
        } 
 
        static private void ValidateKeyOptions(RegistryOptions options) {
            if (options < RegistryOptions.None || options > RegistryOptions.Volatile) { 
                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidRegistryOptionsCheck, ExceptionArgument.options);
            }
        }
 
        static private void ValidateKeyView(RegistryView view) {
            if (view != RegistryView.Default && view != RegistryView.Registry32 && view != RegistryView.Registry64) { 
                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidRegistryViewCheck, ExceptionArgument.view); 
            }
        } 


#if FEATURE_MACL
        static private void ValidateKeyRights(int rights) { 
            if(0 != (rights & ~((int) RegistryRights.FullControl))) {
                // We need to throw SecurityException here for compatiblity reason, 
                // although UnauthorizedAccessException will make more sense. 
                ThrowHelper.ThrowSecurityException(ExceptionResource.Security_RegistryPermission);
            } 
        }
#endif
        // 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] 
    public enum RegistryValueOptions {
        None = 0,
        DoNotExpandEnvironmentNames = 1
    } 

    // the name for this API is meant to mimic FileMode, which has similar values 
 
    public enum RegistryKeyPermissionCheck {
        Default = 0, 
        ReadSubTree = 1,
        ReadWriteSubTree = 2
    }
 
#endif // !FEATURE_PAL
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

/* 
  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
  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 hack.  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.

*/ 

 
namespace Microsoft.Win32 { 

    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Security;
#if !FEATURE_PAL && FEATURE_MACL 
    using System.Security.AccessControl;
#endif 
    using System.Security.Permissions; 
    using System.Text;
    using System.Threading; 
    using System.IO;
    using System.Runtime.Remoting;
    using System.Runtime.InteropServices;
    using Microsoft.Win32.SafeHandles; 
    using System.Runtime.Versioning;
    using System.Globalization; 
    using System.Diagnostics.Contracts; 

#if !FEATURE_PAL 

    /**
     * Registry hive values.  Useful only for GetRemoteBaseKey
     */ 
    [Serializable]
[System.Runtime.InteropServices.ComVisible(true)] 
    public 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),
        DynData = unchecked((int)0x80000006), 
    } 

    /** 
     * 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) 
     */ 
#if FEATURE_REMOTING
    [ComVisible(true)] 
    public sealed class RegistryKey : MarshalByRefObject, IDisposable
#if false
    {}
#endif 
#else
    [ComVisible(true)] 
    public sealed class RegistryKey : IDisposable 
#endif
    { 

        // 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));
        internal static readonly IntPtr HKEY_DYN_DATA             = new IntPtr(unchecked((int)0x80000006)); 

        // 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".
        // 
        private const int STATE_SYSTEMKEY    = 0x0002;

        // Access
        // 
        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", 
                "HKEY_DYN_DATA"
                };

        // 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; 

        [System.Security.SecurityCritical /*auto-generated*/]
        private SafeRegistryHandle hkey = null;
        private int state = 0; 
        private String keyName;
        private bool remoteKey = false; 
        private RegistryKeyPermissionCheck checkMode; 
        private 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. 
         *
         * This key is bound to hkey, if writable is false then no write operations 
         * will be allowed. 
         */
        [System.Security.SecurityCritical]  // auto-generated 
        private RegistryKey(SafeRegistryHandle  hkey, bool writable, RegistryView view)
            : this(hkey, writable, false, false, false, view) {
        }
 

        /** 
         * Creates a RegistryKey. 
         *
         * This key is bound to hkey, if writable is false 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. 
         */
        [System.Security.SecurityCritical]  // auto-generated 
        private RegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey, bool remoteKey, bool isPerfData, RegistryView view) { 
            this.hkey = hkey;
            this.keyName = ""; 
            this.remoteKey = remoteKey;
            this.regView = view;
            if (systemkey) {
                this.state |= STATE_SYSTEMKEY; 
            }
            if (writable) { 
                this.state |= STATE_WRITEACCESS; 
            }
            if (isPerfData) 
                this.state |= STATE_PERF_DATA;
            ValidateKeyView(view);
        }
 
        /**
         * Closes this key, flushes it to disk if the contents have been modified. 
         */ 
        public void Close() {
            Dispose(true); 
        }

        [System.Security.SecuritySafeCritical]  // auto-generated
        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 ---- 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 of ---- 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); 
                }
            } 
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated 
        public void Flush() {
            if (hkey != null) {
                 if (IsDirty()) {
                     Win32Native.RegFlushKey(hkey); 
                }
            } 
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated 
#if FEATURE_CORECLR
        void IDisposable.Dispose()
#if false // ugly hack to fix syntax for TrimSrc parser, which ignores #if directives
        { 
        }
#endif 
#else 
        public void Dispose()
#endif 
        {
            Dispose(true);
        }
 
        /**
         * Creates a new subkey, or opens an existing one. 
         * 
         * @param subkey Name or path to subkey to create or open.
         * 
         * @return the subkey, or null if the operation failed.
         */
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public RegistryKey CreateSubKey(String subkey) {
            return CreateSubKey(subkey, checkMode); 
        } 

        [ComVisible(false)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public RegistryKey CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck)
        { 
            return CreateSubKeyInternal(subkey, permissionCheck, null, RegistryOptions.None);
        } 
 
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public RegistryKey CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options)
        {
            return CreateSubKeyInternal(subkey, permissionCheck, null, options); 
        }
 
 
#if !FEATURE_PAL && FEATURE_MACL
        [ComVisible(false)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public unsafe RegistryKey CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck,  RegistrySecurity registrySecurity)
        { 
            return CreateSubKeyInternal(subkey, permissionCheck, registrySecurity, RegistryOptions.None);
        } 
 
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public unsafe RegistryKey CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck,  RegistryOptions registryOptions, RegistrySecurity registrySecurity)
        {
            return CreateSubKeyInternal(subkey, permissionCheck, registrySecurity, registryOptions); 
        }
#endif 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private unsafe RegistryKey CreateSubKeyInternal(String subkey, RegistryKeyPermissionCheck permissionCheck, object registrySecurityObj, RegistryOptions registryOptions)
        { 
            ValidateKeyOptions(registryOptions);
            ValidateKeyName(subkey); 
            ValidateKeyMode(permissionCheck); 
            EnsureWriteable();
            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash 

            // only keys opened under read mode is not writable
            if (!remoteKey) {
                RegistryKey key = InternalOpenSubKey(subkey, (permissionCheck != RegistryKeyPermissionCheck.ReadSubTree)); 
                if (key != null)  { // Key already exits
                    CheckPermission(RegistryInternalCheck.CheckSubKeyWritePermission, subkey, false, RegistryKeyPermissionCheck.Default); 
                    CheckPermission(RegistryInternalCheck.CheckSubTreePermission, subkey, false, permissionCheck); 
                    key.checkMode = permissionCheck;
                    return key; 
                }
            }

            CheckPermission(RegistryInternalCheck.CheckSubKeyCreatePermission, subkey, false, RegistryKeyPermissionCheck.Default); 

            Win32Native.SECURITY_ATTRIBUTES secAttrs = null; 
#if !FEATURE_PAL && FEATURE_MACL 
            RegistrySecurity registrySecurity = (RegistrySecurity)registrySecurityObj;
            // For ACL's, get the security descriptor from the RegistrySecurity. 
            if (registrySecurity != null) {
                secAttrs = new Win32Native.SECURITY_ATTRIBUTES();
                secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
 
                byte[] sd = registrySecurity.GetSecurityDescriptorBinaryForm();
                // We allocate memory on the stack to improve the speed. 
                // So this part of code can't be refactored into a method. 
                byte* pSecDescriptor = stackalloc byte[sd.Length];
                Buffer.memcpy(sd, 0, pSecDescriptor, 0, sd.Length); 
                secAttrs.pSecurityDescriptor = pSecDescriptor;
            }
#endif
            int disposition = 0; 

            // By default, the new key will be writable. 
            SafeRegistryHandle result = null; 
            int ret = Win32Native.RegCreateKeyEx(hkey,
                subkey, 
                0,
                null,
                (int)registryOptions /* specifies if the key is volatile */,
                GetRegistryKeyAccess(permissionCheck != RegistryKeyPermissionCheck.ReadSubTree, regView), 
                secAttrs,
                out result, 
                out disposition); 

            if (ret == 0 && !result.IsInvalid) { 
                RegistryKey key = new RegistryKey(result, (permissionCheck != RegistryKeyPermissionCheck.ReadSubTree), false, remoteKey, false, regView);
                CheckPermission(RegistryInternalCheck.CheckSubTreePermission, subkey, false, permissionCheck);
                key.checkMode = permissionCheck;
 
                if (subkey.Length == 0)
                    key.keyName = keyName; 
                else 
                    key.keyName = keyName + "\\" + subkey;
                return key; 
            }
            else if (ret != 0) // syscall failed, ret is an error code.
                Win32Error(ret, keyName + "\\" + subkey);  // Access denied?
 
            BCLDebug.Assert(false, "Unexpected code path in RegistryKey::CreateSubKey");
            return null; 
        } 

        /** 
         * Deletes the specified subkey. Will throw an exception if the subkey has
         * subkeys. To delete a tree of subkeys use, DeleteSubKeyTree.
         *
         * @param subkey SubKey to delete. 
         *
         * @exception InvalidOperationException thrown if the subkey has child subkeys. 
         */ 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void DeleteSubKey(String subkey) {
            DeleteSubKey(subkey, true);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)] 
        public void DeleteSubKey(String subkey, bool throwOnMissingSubKey) {
            ValidateKeyName(subkey); 
            EnsureWriteable();
            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash
            CheckPermission(RegistryInternalCheck.CheckSubKeyWritePermission, subkey, false, RegistryKeyPermissionCheck.Default);
 
            // Open the key we are deleting and check for children. Be sure to
            // explicitly call close to avoid keeping an extra HKEY open. 
            // 
            RegistryKey key = InternalOpenSubKey(subkey,false);
            if (key != null) { 
                try {
                    if (key.InternalSubKeyCount() > 0) {
                        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_RegRemoveSubKey);
                    } 
                }
                finally { 
                    key.Close(); 
                }
 
                int ret;

                try {
                    ret = Win32Native.RegDeleteKeyEx(hkey, subkey, (int)regView, 0); 
                }
                catch (EntryPointNotFoundException) { 
                    // 
                    ret = Win32Native.RegDeleteKey(hkey, subkey);
                } 

                if (ret!=0) {
                    if (ret == Win32Native.ERROR_FILE_NOT_FOUND) {
                        if (throwOnMissingSubKey) 
                            ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegSubKeyAbsent);
                    } 
                    else 
                        Win32Error(ret, null);
                } 
            }
            else { // there is no key which also means there is no subkey
                if (throwOnMissingSubKey)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegSubKeyAbsent); 
            }
        } 
 
        /**
         * Recursively deletes a subkey and any child subkeys. 
         *
         * @param subkey SubKey to delete.
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void DeleteSubKeyTree(String subkey) { 
            DeleteSubKeyTree(subkey, true /*throwOnMissingSubKey*/);
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public void DeleteSubKeyTree(String subkey, Boolean throwOnMissingSubKey) { 
            ValidateKeyName(subkey); 

            // Security concern: Deleting a hive's "" subkey would delete all 
            // of that hive's contents.  Don't allow "".
            if (subkey.Length==0 && IsSystemKey()) {
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegKeyDelHive);
            } 

            EnsureWriteable(); 
 
            subkey = FixupName(subkey); // Fixup multiple slashes to a single slash
            CheckPermission(RegistryInternalCheck.CheckSubTreeWritePermission, subkey, false, RegistryKeyPermissionCheck.Default); 

            RegistryKey key = InternalOpenSubKey(subkey, true);
            if (key != null) {
                try { 
                    if (key.InternalSubKeyCount() > 0) {
                        String[] keys = key.InternalGetSubKeyNames(); 
 
                        for (int i=0; i 0) { 
                        String[] keys = key.InternalGetSubKeyNames(); 

                        for (int i=0; i= 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,false, isPerf, view);
            key.checkMode = RegistryKeyPermissionCheck.Default;
            key.keyName = hkeyNames[index];
            return key; 
        }
 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        [ComVisible(false)]
        public static RegistryKey OpenBaseKey(RegistryHive hKey, RegistryView view) {
            ValidateKeyView(view); 
            CheckUnmanagedCodePermission();
            return GetBaseKey((IntPtr)((int)hKey), view); 
        } 

        /** 
         * Retrieves a new RegistryKey that represents the requested key on a foreign
         * machine.  Valid values for hKey are members of the RegistryHive enum, or
         * Win32 integers such as:
         * 
         * 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. 
         * @param machineName the machine to connect to
         * 
         * @return the RegistryKey requested. 
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey, String machineName) {
            return OpenRemoteBaseKey(hKey, machineName, RegistryView.Default); 
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey, String machineName, RegistryView view) {
            if (machineName==null)
                throw new ArgumentNullException("machineName"); 
            int index = (int)hKey & 0x0FFFFFFF;
            if (index < 0 || index >= hkeyNames.Length || ((int)hKey & 0xFFFFFFF0) != 0x80000000) { 
                throw new ArgumentException(Environment.GetResourceString("Arg_RegKeyOutOfRange")); 
            }
            ValidateKeyView(view); 

            CheckUnmanagedCodePermission();
            // connect to the specified remote registry
            SafeRegistryHandle foreignHKey = null; 
            int ret = Win32Native.RegConnectRegistry(machineName, new SafeRegistryHandle(new IntPtr((int)hKey), false), out foreignHKey);
 
            if (ret == Win32Native.ERROR_DLL_INIT_FAILED) 
                // return value indicates an error occurred
                throw new ArgumentException(Environment.GetResourceString("Arg_DllInitFailure")); 

            if (ret != 0)
                Win32ErrorStatic(ret, null);
 
            if (foreignHKey.IsInvalid)
                // return value indicates an error occurred 
                throw new ArgumentException(Environment.GetResourceString("Arg_RegKeyNoRemoteConnect", machineName)); 

            RegistryKey key = new RegistryKey(foreignHKey, true, false, true, ((IntPtr) hKey) == HKEY_PERFORMANCE_DATA, view); 
            key.checkMode = RegistryKeyPermissionCheck.Default;
            key.keyName = hkeyNames[index];
            return key;
        } 

        /** 
         * Retrieves a subkey. If readonly is true, then the subkey is opened with 
         * read-only access.
         * 
         * @param name Name or path of subkey to open.
         * @param readonly Set to true if you only need readonly access.
         *
         * @return the Subkey requested, or null if the operation failed. 
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public RegistryKey OpenSubKey(string name, bool writable ) { 
            ValidateKeyName(name);
            EnsureNotDisposed();
            name = FixupName(name); // Fixup multiple slashes to a single slash
 
            CheckPermission(RegistryInternalCheck.CheckOpenSubKeyWithWritablePermission, name, writable, RegistryKeyPermissionCheck.Default);
            SafeRegistryHandle result = null; 
            int ret = Win32Native.RegOpenKeyEx(hkey, name, 0, GetRegistryKeyAccess(writable, 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 == Win32Native.ERROR_ACCESS_DENIED || ret == Win32Native.ERROR_BAD_IMPERSONATION_LEVEL) {
                // We need to throw SecurityException here for compatibility reasons, 
                // although UnauthorizedAccessException will make more sense.
                ThrowHelper.ThrowSecurityException(ExceptionResource.Security_RegistryPermission);
            }
 
            return null;
        } 
 
#if FEATURE_MACL
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public RegistryKey OpenSubKey(String name, RegistryKeyPermissionCheck permissionCheck) {
            ValidateKeyMode(permissionCheck); 
            return InternalOpenSubKey(name, permissionCheck, GetRegistryKeyAccess(permissionCheck, regView)); 
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public RegistryKey OpenSubKey(String name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights) {
            return InternalOpenSubKey(name, permissionCheck, (int)rights); 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private RegistryKey InternalOpenSubKey(String name, RegistryKeyPermissionCheck permissionCheck, int rights) {
            ValidateKeyName(name); 
            ValidateKeyMode(permissionCheck);
 
            ValidateKeyRights(rights); 

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

            CheckPermission(RegistryInternalCheck.CheckOpenSubKeyPermission, name, false, permissionCheck);
            CheckPermission(RegistryInternalCheck.CheckSubTreePermission, name, false, permissionCheck); 
            SafeRegistryHandle result = null;
            int ret = Win32Native.RegOpenKeyEx(hkey, name, 0, (rights | (int)regView), out result); 
            if (ret == 0 && !result.IsInvalid) { 
                RegistryKey key = new RegistryKey(result, (permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree), false, remoteKey, false, regView);
                key.keyName = keyName + "\\" + name; 
                key.checkMode = permissionCheck;
                return key;
            }
 
            // Return null if we didn't find the key.
            if (ret == Win32Native.ERROR_ACCESS_DENIED || ret == Win32Native.ERROR_BAD_IMPERSONATION_LEVEL) { 
                // We need to throw SecurityException here for compatiblity reason, 
                // although UnauthorizedAccessException will make more sense.
                ThrowHelper.ThrowSecurityException(ExceptionResource.Security_RegistryPermission); 
            }

            return null;
        } 
#endif
 
        // 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
        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        internal RegistryKey InternalOpenSubKey(String name, bool writable) {
            ValidateKeyName(name); 
            EnsureNotDisposed();
 
            SafeRegistryHandle result = null; 
            int ret = Win32Native.RegOpenKeyEx(hkey, name, 0, GetRegistryKeyAccess(writable, 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 null if the operation failed.
         */ 
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public RegistryKey OpenSubKey(String name) { 
            return OpenSubKey(name, false);
        }

        /** 
         * Retrieves the count of subkeys.
         * 
         * @return a count of subkeys. 
         */
        public int SubKeyCount { 
            [System.Security.SecuritySafeCritical]  // auto-generated
            get {
                CheckPermission(RegistryInternalCheck.CheckKeyReadPermission, null, false, RegistryKeyPermissionCheck.Default);
                return InternalSubKeyCount(); 
            }
        } 
 
        [ComVisible(false)]
        public RegistryView View { 
            [System.Security.SecuritySafeCritical]
            get {
                EnsureNotDisposed();
                return regView; 
            }
        } 
 
        [ComVisible(false)]
        public SafeRegistryHandle Handle { 
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            [System.Security.SecurityCritical]
            [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
            get {
                EnsureNotDisposed(); 
                int ret = Win32Native.ERROR_INVALID_HANDLE; 
                if (IsSystemKey()) {
                    IntPtr baseKey = (IntPtr)0; 
                    switch (keyName) {
                        case "HKEY_CLASSES_ROOT":
                            baseKey = HKEY_CLASSES_ROOT;
                            break; 
                        case "HKEY_CURRENT_USER":
                            baseKey = HKEY_CURRENT_USER; 
                            break; 
                        case "HKEY_LOCAL_MACHINE":
                            baseKey = HKEY_LOCAL_MACHINE; 
                            break;
                        case "HKEY_USERS":
                            baseKey = HKEY_USERS;
                            break; 
                        case "HKEY_PERFORMANCE_DATA":
                            baseKey = HKEY_PERFORMANCE_DATA; 
                            break; 
                        case "HKEY_CURRENT_CONFIG":
                            baseKey = HKEY_CURRENT_CONFIG; 
                            break;
                        case "HKEY_DYN_DATA":
                            baseKey = HKEY_DYN_DATA;
                            break; 
                        default:
                            Win32Error(ret, null); 
                            break; 
                    }
                    // open the base key so that RegistryKey.Handle will return a valid handle 
                    SafeRegistryHandle result;
                    ret = Win32Native.RegOpenKeyEx(baseKey, null, 0, GetRegistryKeyAccess(IsWritable(), regView), out result);
                    if (ret == 0 && !result.IsInvalid) {
                        return result; 
                    }
                    else { 
                        Win32Error(ret, null); 
                    }
                } 
                else {
                    return hkey;
                }
                throw new IOException(Win32Native.GetMessage(ret), ret); 
            }
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        [System.Security.SecurityCritical]
        [ComVisible(false)]
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public static RegistryKey FromHandle(SafeRegistryHandle handle) { 
            return FromHandle(handle, RegistryView.Default);
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        [System.Security.SecurityCritical]
        [ComVisible(false)]
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public static RegistryKey FromHandle(SafeRegistryHandle handle, RegistryView view) { 
            if (handle == null) throw new ArgumentNullException("handle");
            ValidateKeyView(view); 
 
            return new RegistryKey(handle, true /* isWritable */, view);
        } 

        [System.Security.SecurityCritical]  // auto-generated
        internal int InternalSubKeyCount() {
                EnsureNotDisposed(); 

                int subkeys = 0; 
                int junk = 0; 
                int ret = Win32Native.RegQueryInfoKey(hkey,
                                          null, 
                                          null,
                                          Win32Native.NULL,
                                          ref subkeys,  // subkeys
                                          null, 
                                          null,
                                          ref junk,     // values 
                                          null, 
                                          null,
                                          null, 
                                          null);

                if (ret != 0)
                    Win32Error(ret, null); 
                return subkeys;
        } 
 
        /**
         * Retrieves an array of strings containing all the subkey names. 
         *
         * @return all subkey names.
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        public String[] GetSubKeyNames() {
            CheckPermission(RegistryInternalCheck.CheckKeyReadPermission, null, false, RegistryKeyPermissionCheck.Default); 
            return InternalGetSubKeyNames(); 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal String[] InternalGetSubKeyNames() {
            EnsureNotDisposed();
            int subkeys = InternalSubKeyCount(); 
            String[] names = new String[subkeys];  // Returns 0-length array if empty.
 
            if (subkeys > 0) { 
                StringBuilder name = new StringBuilder(MaxKeyLength+1);
                int namelen; 

                for (int i=0; i 0) { 
                StringBuilder name = new StringBuilder(MaxValueLength+1); 
                int namelen;
 
                for (int i=0; inull is returned if the value
         * doesn't exist. 
         *
         * Note that name 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. 
         */
        [System.Security.SecuritySafeCritical]  // auto-generated 
        public Object GetValue(String name) {
            CheckPermission(RegistryInternalCheck.CheckValueReadPermission, name, false, RegistryKeyPermissionCheck.Default);
            return InternalGetValue(name, null, false, true);
        } 

        /** 
         * Retrieves the specified value. defaultValue is returned if the value doesn't exist. 
         *
         * Note that name 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.  On
         * Win95, the default value is always an empty key of type REG_SZ. 
         * Win98 supports default values of any type, but defaults to REG_SZ.
         * 
         * @param name Name of value to retrieve. 
         * @param defaultValue Value to return if name doesn't exist.
         * 
         * @return the data associated with the value.
         */
        [System.Security.SecuritySafeCritical]  // auto-generated
        public Object GetValue(String name, Object defaultValue) { 
            CheckPermission(RegistryInternalCheck.CheckValueReadPermission, name, false, RegistryKeyPermissionCheck.Default);
            return InternalGetValue(name, defaultValue, false, true); 
        } 

        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ComVisible(false)]
        public Object GetValue(String name, Object defaultValue, RegistryValueOptions options) {
            if( options < RegistryValueOptions.None || options > RegistryValueOptions.DoNotExpandEnvironmentNames) {
                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)options), "options"); 
            }
            bool doNotExpand = (options == RegistryValueOptions.DoNotExpandEnvironmentNames); 
            CheckPermission(RegistryInternalCheck.CheckValueReadPermission, name, false, RegistryKeyPermissionCheck.Default); 
            return InternalGetValue(name, defaultValue, doNotExpand, true);
        } 

        [System.Security.SecurityCritical]  // auto-generated
        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 = Win32Native.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 (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 
                BCLDebug.Assert(false, "[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize"); 
                datasize = 0;
            } 


            switch (type) {
            case Win32Native.REG_NONE: 
            case Win32Native.REG_DWORD_BIG_ENDIAN:
            case Win32Native.REG_BINARY: { 
                                 byte[] blob = new byte[datasize]; 
                                 ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
                                 data = blob; 
                             }
                             break;
            case Win32Native.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 Win32Native.REG_BINARY; 
                                 }
                                 long blob = 0; 
                                 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);
 
                                 data = blob;
                             } 
                             break; 
            case Win32Native.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 Win32Native.REG_QWORD;
                                 } 
                                 int blob = 0;
                                 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);
 
                                 data = blob;
                             }
                             break;
 
            case Win32Native.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(Environment.GetResourceString("Arg_RegGetOverflowBug"), e); 
                                     }
                                 } 
                                 char[] blob = new char[datasize/2]; 

                                 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);
                                 }
                                 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 Win32Native.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(Environment.GetResourceString("Arg_RegGetOverflowBug"), e);
                                     }
                                 } 
                                 char[] blob = new char[datasize/2];
 
                                 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);
                                 }
                                 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 Win32Native.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(Environment.GetResourceString("Arg_RegGetOverflowBug"), e);
                                     } 
                                 }
                                 char[] blob = new char[datasize/2]; 
 
                                 ret = Win32Native.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(Environment.GetResourceString("Arg_RegGetOverflowBug"), e);
                                     } 
                                     blob[blob.Length - 1] = (char)0;
                                 } 
 

                                 IList strings = new List(); 
                                 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) {
                                         BCLDebug.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 Win32Native.REG_LINK:
            default: 
                break; 
            }
 
            return data;
        }

 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)] 
        public RegistryValueKind GetValueKind(string name) { 
            CheckPermission(RegistryInternalCheck.CheckValueReadPermission, name, false, RegistryKeyPermissionCheck.Default);
            EnsureNotDisposed(); 

            int type = 0;
            int datasize = 0;
            int ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, (byte[])null, ref datasize); 
            if (ret != 0)
                Win32Error(ret, null); 
            if (type == Win32Native.REG_NONE) 
                return RegistryValueKind.None;
            else if (!Enum.IsDefined(typeof(RegistryValueKind), type)) 
                return RegistryValueKind.Unknown;
            else
                return (RegistryValueKind) type;
        } 

        /** 
         * Retrieves the current state of the dirty property. 
         *
         * A key is marked as dirty if any operation has occured that modifies the 
         * contents of the key.
         *
         * @return true if the key has been modified.
         */ 
        private bool IsDirty() {
            return (this.state & STATE_DIRTY) != 0; 
        } 

        private bool IsSystemKey() { 
            return (this.state & STATE_SYSTEMKEY) != 0;
        }

        private bool IsWritable() { 
            return (this.state & STATE_WRITEACCESS) != 0;
        } 
 
        private bool IsPerfDataKey() {
            return (this.state & STATE_PERF_DATA) != 0; 
        }

        public String Name {
            [System.Security.SecuritySafeCritical]  // auto-generated 
            get {
                EnsureNotDisposed(); 
                return keyName; 
            }
        } 

        private void SetDirty() {
            this.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); 
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ComVisible(false)]
        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(Environment.GetResourceString("Arg_RegValStrLenBug"));
            } 
 
            if (!Enum.IsDefined(typeof(RegistryValueKind), valueKind))
                throw new ArgumentException(Environment.GetResourceString("Arg_RegBadKeyKind"), "valueKind"); 

            EnsureWriteable();

            if (!remoteKey && ContainsRegistryValue(name)) { // Existing key 
                CheckPermission(RegistryInternalCheck.CheckValueWritePermission, name, false, RegistryKeyPermissionCheck.Default);
            } 
             else { // Creating a new value 
                CheckPermission(RegistryInternalCheck.CheckValueCreatePermission, name, false, RegistryKeyPermissionCheck.Default);
            } 

            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= 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;
            }
 
        }
 
        // 
        // Read/Write/Create SubKey Permission
        // 
        private void GetSubKeyReadPermission(string subkeyName, out RegistryPermissionAccess access, out string path) {
            access = RegistryPermissionAccess.Read;
            path   = keyName + "\\" + subkeyName + "\\.";
        } 
        private void GetSubKeyWritePermission(string subkeyName, out RegistryPermissionAccess access, out string path) {
            // If we want to open a subkey of a read-only key as writeable, we need to do the check. 
            access = RegistryPermissionAccess.Write; 
            path   = keyName + "\\" + subkeyName + "\\.";
        } 
        private void GetSubKeyCreatePermission(string subkeyName, out RegistryPermissionAccess access, out string path) {
            access = RegistryPermissionAccess.Create;
            path   = keyName + "\\" + subkeyName + "\\.";
        } 

        // 
        // Read/Write/ReadWrite SubTree Permission 
        //
        private void GetSubTreeReadPermission(string subkeyName, out RegistryPermissionAccess access, out string path) { 
            access = RegistryPermissionAccess.Read;
            path   = keyName + "\\" + subkeyName + "\\";
        }
        private void GetSubTreeWritePermission(string subkeyName, out RegistryPermissionAccess access, out string path) { 
            access = RegistryPermissionAccess.Write;
            path   = keyName + "\\" + subkeyName + "\\"; 
        } 
        private void GetSubTreeReadWritePermission(string subkeyName, out RegistryPermissionAccess access, out string path) {
            access = RegistryPermissionAccess.Write | RegistryPermissionAccess.Read; 
            path   = keyName + "\\" + subkeyName;
        }

        // 
        // Read/Write/Create Value Permission
        // 
        private void GetValueReadPermission(string valueName, out RegistryPermissionAccess access, out string path) { 
            access = RegistryPermissionAccess.Read;
            path   = keyName+"\\"+valueName; 
        }
        private void GetValueWritePermission(string valueName, out RegistryPermissionAccess access, out string path) {
            access = RegistryPermissionAccess.Write;
            path   = keyName+"\\"+valueName; 
        }
        private void GetValueCreatePermission(string valueName, out RegistryPermissionAccess access, out string path) { 
            access = RegistryPermissionAccess.Create; 
            path   = keyName+"\\"+valueName;
        } 

        // Read Key Permission
        private void GetKeyReadPermission(out RegistryPermissionAccess access, out string path) {
           access = RegistryPermissionAccess.Read; 
           path   = keyName + "\\.";
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        private void CheckPermission(RegistryInternalCheck check, string item, bool subKeyWritable, RegistryKeyPermissionCheck subKeyCheck) { 
            bool demand = false;
            RegistryPermissionAccess access = RegistryPermissionAccess.NoAccess;
            string path = null;
 
#if !FEATURE_CORECLR
            if (CodeAccessSecurityEngine.QuickCheckForAllDemands()) { 
                return; // full trust fast path 
            }
#endif // !FEATURE_CORECLR 

            switch (check) {
                //
                // Read/Write/Create SubKey Permission 
                //
                case RegistryInternalCheck.CheckSubKeyReadPermission: 
                    if (remoteKey) { 
                        CheckUnmanagedCodePermission();
                    } 
                    else {
                        BCLDebug.Assert(checkMode == RegistryKeyPermissionCheck.Default, "Should be called from a key opened under default mode only!");
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        demand = true;
                        GetSubKeyReadPermission(item, out access, out path); 
                    } 
                    break;
                case RegistryInternalCheck.CheckSubKeyWritePermission: 
                    if (remoteKey) {
                        CheckUnmanagedCodePermission();
                    }
                    else { 
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow creating sub key under read-only key!");
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)"); 
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            demand = true; 
                            GetSubKeyWritePermission(item, out access, out path);
                        }
                    }
                    break; 
                case RegistryInternalCheck.CheckSubKeyCreatePermission:
                    if (remoteKey) { 
                        CheckUnmanagedCodePermission(); 
                    }
                    else { 
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow creating sub key under read-only key!");
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)");
                        if( checkMode == RegistryKeyPermissionCheck.Default) { 
                            demand = true;
                            GetSubKeyCreatePermission(item, out access, out path); 
                        } 
                    }
                    break; 
                //
                // Read/Write/ReadWrite SubTree Permission
                //
                case RegistryInternalCheck.CheckSubTreeReadPermission: 
                    if (remoteKey) {
                        CheckUnmanagedCodePermission(); 
                    } 
                    else {
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)"); 
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)");
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            demand = true;
                            GetSubTreeReadPermission(item, out access, out path); 
                        }
                    } 
                    break; 
                case RegistryInternalCheck.CheckSubTreeWritePermission:
                    if (remoteKey) { 
                        CheckUnmanagedCodePermission();
                    }
                    else {
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow writing value to read-only key!"); 
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        if( checkMode == RegistryKeyPermissionCheck.Default) { 
                            demand = true;
                            GetSubTreeWritePermission(item, out access, out path); 
                        }
                    }
                    break;
                case RegistryInternalCheck.CheckSubTreeReadWritePermission: 
                    if (remoteKey) {
                        CheckUnmanagedCodePermission(); 
                    } 
                    else {
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)"); 
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)");
                        // If we want to open a subkey of a read-only key as writeable, we need to do the check.
                        demand = true;
                        GetSubTreeReadWritePermission(item, out access, out path); 
                    }
                    break; 
                // 
                // Read/Write/Create Value Permission
                // 
                case RegistryInternalCheck.CheckValueReadPermission:
                    ///*** no remoteKey check ***///
                    BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                    BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                    if( checkMode == RegistryKeyPermissionCheck.Default) {
                        // only need to check for default mode (dynamice check) 
                        demand = true; 
                        GetValueReadPermission(item, out access, out path);
                    } 
                    break;
                case RegistryInternalCheck.CheckValueWritePermission:
                    if (remoteKey) {
                        CheckUnmanagedCodePermission(); 
                    }
                    else { 
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow writing value to read-only key!"); 
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        // skip the security check if the key is opened under write mode
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            demand = true;
                            GetValueWritePermission(item, out access, out path); 
                        }
                    } 
                    break; 
                case RegistryInternalCheck.CheckValueCreatePermission:
                    if (remoteKey) { 
                        CheckUnmanagedCodePermission();
                    }
                    else {
                        BCLDebug.Assert(checkMode != RegistryKeyPermissionCheck.ReadSubTree, "We shouldn't allow creating value under read-only key!"); 
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 
                        // skip the security check if the key is opened under write mode 
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            demand = true; 
                            GetValueCreatePermission(item, out access, out path);
                        }
                    }
                    break; 
                //
                // CheckKeyReadPermission 
                // 
                case RegistryInternalCheck.CheckKeyReadPermission:
                    ///*** no remoteKey check ***/// 
                    if( checkMode == RegistryKeyPermissionCheck.Default) {
                        BCLDebug.Assert(item == null, "CheckKeyReadPermission should never have a non-null item parameter!");
                        BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                        BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)"); 

                        // only need to check for default mode (dynamice check) 
                        demand = true; 
                        GetKeyReadPermission(out access, out path);
                    } 
                    break;
                //
                // CheckSubTreePermission
                // 
                case RegistryInternalCheck.CheckSubTreePermission:
                    BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)"); 
                    if( subKeyCheck == RegistryKeyPermissionCheck.ReadSubTree) { 
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            if( remoteKey) { 
                                CheckUnmanagedCodePermission();
                            }
                            else {
                                demand = true; 
                                GetSubTreeReadPermission(item, out access, out path);
                            } 
                        } 
                    }
                    else if(subKeyCheck == RegistryKeyPermissionCheck.ReadWriteSubTree) { 
                        if( checkMode != RegistryKeyPermissionCheck.ReadWriteSubTree) {
                            if( remoteKey) {
                                CheckUnmanagedCodePermission();
                            } 
                            else {
                                demand = true; 
                                GetSubTreeReadWritePermission(item, out access, out path); 
                            }
                        } 
                    }
                    break;

                // 
                // CheckOpenSubKeyWithWritablePermission uses the 'subKeyWritable' parameter
                // 
                case RegistryInternalCheck.CheckOpenSubKeyWithWritablePermission: 
                    BCLDebug.Assert(subKeyCheck == RegistryKeyPermissionCheck.Default, "subKeyCheck should be Default (unused)");
                    // If the parent key is not opened under default mode, we have access already. 
                    // If the parent key is opened under default mode, we need to check for permission.
                    if(checkMode == RegistryKeyPermissionCheck.Default) {
                        if( remoteKey) {
                            CheckUnmanagedCodePermission(); 
                        }
                        else { 
                            demand = true; 
                            GetSubKeyReadPermission(item, out access, out path);
                        } 
                        break;
                    }
                    if( subKeyWritable && (checkMode == RegistryKeyPermissionCheck.ReadSubTree)) {
                        if( remoteKey) { 
                            CheckUnmanagedCodePermission();
                        } 
                        else { 
                            demand = true;
                            GetSubTreeReadWritePermission(item, out access, out path); 
                        }
                        break;
                    }
                    break; 

                // 
                // CheckOpenSubKeyPermission uses the 'subKeyCheck' parameter 
                //
                case RegistryInternalCheck.CheckOpenSubKeyPermission: 
                    BCLDebug.Assert(subKeyWritable == false, "subKeyWritable should be false (unused)");
                    if(subKeyCheck == RegistryKeyPermissionCheck.Default) {
                        if( checkMode == RegistryKeyPermissionCheck.Default) {
                            if(remoteKey) { 
                                CheckUnmanagedCodePermission();
                            } 
                            else { 
                                demand = true;
                                GetSubKeyReadPermission(item, out access, out path); 
                            }
                        }
                    }
                    break; 

                default: 
                    BCLDebug.Assert(false, "CheckPermission default switch case should never be hit!"); 
                    break;
            } 

            if (demand) {
                new RegistryPermission(access, path).Demand();
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        static private void  CheckUnmanagedCodePermission() {
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); 
        }

        [System.Security.SecurityCritical]  // auto-generated
        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;
        } 

        [System.Security.SecurityCritical]  // auto-generated
        private void EnsureNotDisposed(){
            if (hkey == null) { 
                ThrowHelper.ThrowObjectDisposedException(keyName, ExceptionResource.ObjectDisposed_RegKeyClosed);
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        private void EnsureWriteable() {
            EnsureNotDisposed();
            if (!IsWritable()) {
                ThrowHelper.ThrowUnauthorizedAccessException(ExceptionResource.UnauthorizedAccess_RegistryNoWrite); 
            }
        } 
 
        static int GetRegistryKeyAccess(bool isWritable, RegistryView view) {
            int winAccess; 
            if (!isWritable) {
                winAccess = Win32Native.KEY_READ;
            }
            else { 
                winAccess = Win32Native.KEY_READ | Win32Native.KEY_WRITE;
            } 
            winAccess = winAccess | (int)view; 
            return winAccess;
        } 

        static int GetRegistryKeyAccess(RegistryKeyPermissionCheck mode, RegistryView view) {
            int winAccess = 0;
            switch(mode) { 
                case RegistryKeyPermissionCheck.ReadSubTree:
                case RegistryKeyPermissionCheck.Default: 
                    winAccess =  Win32Native.KEY_READ; 
                    break;
 
                case RegistryKeyPermissionCheck.ReadWriteSubTree:
                    winAccess = Win32Native.KEY_READ| Win32Native.KEY_WRITE;
                    break;
 
               default:
                    BCLDebug.Assert(false, "unexpected code path"); 
                    break; 
            }
            winAccess = winAccess | (int)view; 
            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);
            }
 
            int nextSlash = name.IndexOf("\\", StringComparison.OrdinalIgnoreCase);
            int current = 0; 
            while (nextSlash != -1) { 
                if ((nextSlash - current) > MaxKeyLength)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegKeyStrLenBug); 

                current = nextSlash + 1;
                nextSlash = name.IndexOf("\\", current, StringComparison.OrdinalIgnoreCase);
            } 

            if ((name.Length - current) > MaxKeyLength) 
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RegKeyStrLenBug); 

        } 

        static private void ValidateKeyMode(RegistryKeyPermissionCheck mode) {
            if( mode < RegistryKeyPermissionCheck.Default || mode > RegistryKeyPermissionCheck.ReadWriteSubTree) {
                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidRegistryKeyPermissionCheck, ExceptionArgument.mode); 
            }
        } 
 
        static private void ValidateKeyOptions(RegistryOptions options) {
            if (options < RegistryOptions.None || options > RegistryOptions.Volatile) { 
                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidRegistryOptionsCheck, ExceptionArgument.options);
            }
        }
 
        static private void ValidateKeyView(RegistryView view) {
            if (view != RegistryView.Default && view != RegistryView.Registry32 && view != RegistryView.Registry64) { 
                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidRegistryViewCheck, ExceptionArgument.view); 
            }
        } 


#if FEATURE_MACL
        static private void ValidateKeyRights(int rights) { 
            if(0 != (rights & ~((int) RegistryRights.FullControl))) {
                // We need to throw SecurityException here for compatiblity reason, 
                // although UnauthorizedAccessException will make more sense. 
                ThrowHelper.ThrowSecurityException(ExceptionResource.Security_RegistryPermission);
            } 
        }
#endif
        // 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] 
    public enum RegistryValueOptions {
        None = 0,
        DoNotExpandEnvironmentNames = 1
    } 

    // the name for this API is meant to mimic FileMode, which has similar values 
 
    public enum RegistryKeyPermissionCheck {
        Default = 0, 
        ReadSubTree = 1,
        ReadWriteSubTree = 2
    }
 
#endif // !FEATURE_PAL
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK