/// <summary>
        /// Deletes a given subkey and all of its subkeys
        /// </summary>
        /// <param name="registryKeyRoot">Enum of the root key to delete from (e.g. HKEY_LOCAL_MACHINE = LocalMachine)</param>
        /// <param name="subKey">Path of the subkey to be deleted</param>
        /// <param name="registryVersion">Version of the registry to delete from. Can be 32-Bit, 64-Bit, or both</param>
        public void DeleteSubKeyTree(RegistryKeyRoot registryKeyRoot, string subKey, RegistryVersion registryVersion)
        {
            RegistryKey  rk;
            RegistryHive rh;
            RegistryView rv;

            switch (registryVersion)
            {
            case RegistryVersion.Both:
                rh = DetermineRegistryHive(registryKeyRoot);
                rv = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk = RegistryKey.OpenBaseKey(rh, rv);
                rk.DeleteSubKeyTree(subKey);
                rk = DetermineRootKey(registryKeyRoot);
                rk.DeleteSubKeyTree(subKey);
                break;

            case RegistryVersion.Only32Bit:
                rh = DetermineRegistryHive(registryKeyRoot);
                rv = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk = RegistryKey.OpenBaseKey(rh, rv);
                rk.DeleteSubKeyTree(subKey);
                break;

            default:
                rk = DetermineRootKey(registryKeyRoot);
                rk.DeleteSubKeyTree(subKey);
                break;
            }
            rk.Flush();
        }
        /// <summary>
        /// Writes a value to given key
        /// </summary>
        /// <param name="registryKeyRoot">Enum of the root key to read from (e.g. HKEY_LOCAL_MACHINE = LocalMachine)</param>
        /// <param name="key">Path to the key to write to. If part of the given key does not already exist it will be written</param>
        /// <param name="registryVersion">Version of the registry to write to. Can be 32-Bit, 64-Bit, or both</param>
        /// <param name="valueToWrite">Value to write to the key. should be given in the structure (Name, Data)</param>
        public void WriteValue(RegistryKeyRoot registryKeyRoot, string key, RegistryVersion registryVersion,
                               List <KeyValuePair <string, object> > valueToWrite)
        {
            RegistryHive rh;
            RegistryView rv;
            RegistryKey  rk;
            RegistryKey  subKey;

            switch (registryVersion)
            {
            case RegistryVersion.Both:
                rh     = DetermineRegistryHive(registryKeyRoot);
                rv     = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk     = RegistryKey.OpenBaseKey(rh, rv);
                subKey = rk.CreateSubKey(key);
                foreach (var item in valueToWrite)
                {
                    subKey.SetValue(item.Key, item.Value);
                }
                rk     = DetermineRootKey(registryKeyRoot);
                subKey = rk.CreateSubKey(key);
                foreach (var item in valueToWrite)
                {
                    subKey.SetValue(item.Key, item.Value);
                }
                rk.Flush();
                break;

            case RegistryVersion.Only32Bit:
                rh     = DetermineRegistryHive(registryKeyRoot);
                rv     = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk     = RegistryKey.OpenBaseKey(rh, rv);
                subKey = rk.CreateSubKey(key);
                foreach (var item in valueToWrite)
                {
                    subKey.SetValue(item.Key, item.Value);
                }
                rk.Flush();
                break;

            default:
                rk     = DetermineRootKey(registryKeyRoot);
                subKey = rk.CreateSubKey(key);
                foreach (var item in valueToWrite)
                {
                    subKey.SetValue(item.Key, item.Value);
                }
                rk.Flush();
                break;
            }
        }
        /// <summary>
        /// Determines the root key to be accessed
        /// </summary>
        /// <param name="registryKeyRoot"></param>
        /// <returns>Returns the underlying type that's being wrapped</returns>
        internal RegistryKey DetermineRootKey(RegistryKeyRoot registryKeyRoot)
        {
            RegistryKey rk;

            switch (registryKeyRoot)
            {
            case RegistryKeyRoot.LocalMachine:
                rk = Registry.LocalMachine;
                break;

            case RegistryKeyRoot.CurrentConfig:
                rk = Registry.CurrentConfig;
                break;

            case RegistryKeyRoot.ClassesRoot:
                rk = Registry.ClassesRoot;
                break;

            case RegistryKeyRoot.Users:
                rk = Registry.Users;
                break;

                #pragma warning disable 618
            case RegistryKeyRoot.DynData:
                rk = Registry.DynData;
                break;

                #pragma warning restore 618
            case RegistryKeyRoot.PerformanceData:
                rk = Registry.PerformanceData;
                break;

            default:
                rk = Registry.CurrentUser;
                break;
            }

            return(rk);
        }
        /// <summary>
        /// Determines the RegistryHive to be used (the root key but for 32-Bit systems)
        /// </summary>
        /// <param name="registryKeyRoot"></param>
        /// <returns>Returns the RegistryHive (root key)</returns>
        internal RegistryHive DetermineRegistryHive(RegistryKeyRoot registryKeyRoot)
        {
            RegistryHive rh;

            switch (registryKeyRoot)
            {
            case RegistryKeyRoot.LocalMachine:
                rh = RegistryHive.LocalMachine;
                break;

            case RegistryKeyRoot.CurrentConfig:
                rh = RegistryHive.CurrentConfig;
                break;

            case RegistryKeyRoot.ClassesRoot:
                rh = RegistryHive.ClassesRoot;
                break;

            case RegistryKeyRoot.Users:
                rh = RegistryHive.Users;
                break;

                #pragma warning disable 618
            case RegistryKeyRoot.DynData:     // Obsolete; On NT based systems use PerformanceData instead
                rh = RegistryHive.DynData;
                break;

                #pragma warning restore 618
            case RegistryKeyRoot.PerformanceData:
                rh = RegistryHive.PerformanceData;
                break;

            default:
                rh = RegistryHive.CurrentUser;
                break;
            }
            return(rh);
        }
        /// <summary>
        /// Returns the registry key at the path specified
        /// </summary>
        /// <param name="registryKeyRoot">Enum of the root key to read from (e.g. HKEY_LOCAL_MACHINE = LocalMachine)</param>
        /// <param name="keyPath">Path to the key to read from (without the root key)</param>
        /// <param name="registryVersion">Version of the registry to read from. Can be 32-Bit, 64-Bit, or both</param>
        /// <returns></returns>
        public RegistryKeyContainer ReadKey(RegistryKeyRoot registryKeyRoot, string keyPath, RegistryVersion registryVersion)
        {
            var          _32BitValues = new List <KeyValuePair <string, object> >();
            var          _64BitValues = new List <KeyValuePair <string, object> >();
            RegistryHive rh;
            RegistryView rv;
            RegistryKey  rk;
            RegistryKey  sk;

            switch (registryVersion)
            {
            case RegistryVersion.Both:
                rh = DetermineRegistryHive(registryKeyRoot);
                rv = RegistryView.Registry32;
                rk = RegistryKey.OpenBaseKey(rh, rv);
                try
                {
                    sk = rk.OpenSubKey(keyPath);
                    foreach (var valueName in sk.GetValueNames())
                    {
                        _32BitValues.Add(new KeyValuePair <string, object>(valueName, sk.GetValue(valueName)));
                    }
                }
                catch (NullReferenceException)
                {}
                rk = DetermineRootKey(registryKeyRoot);
                try
                {
                    sk = rk.OpenSubKey(keyPath);
                    foreach (var valueName in sk.GetValueNames())
                    {
                        _64BitValues.Add(new KeyValuePair <string, object>(valueName, sk.GetValue(valueName)));
                    }
                }
                catch (NullReferenceException)
                {}
                break;

            case RegistryVersion.Only32Bit:
                rh = DetermineRegistryHive(registryKeyRoot);
                rv = RegistryView.Registry32;
                rk = RegistryKey.OpenBaseKey(rh, rv);
                try
                {
                    sk = rk.OpenSubKey(keyPath);
                    foreach (var valueName in sk.GetValueNames())
                    {
                        _32BitValues.Add(new KeyValuePair <string, object>(valueName, sk.GetValue(valueName)));
                    }
                }
                catch (NullReferenceException) {}
                break;

            default:
                rk = DetermineRootKey(registryKeyRoot);
                try
                {
                    sk = rk.OpenSubKey(keyPath);
                    foreach (var valueName in sk.GetValueNames())
                    {
                        _64BitValues.Add(new KeyValuePair <string, object>(valueName, sk.GetValue(valueName)));
                    }
                }
                catch (NullReferenceException) {}
                break;
            }

            var keyContainer = new RegistryKeyContainer(registryKeyRoot, keyPath, _64BitValues, _32BitValues, registryVersion);

            return(keyContainer);
        }
        /// <summary>
        /// Deletes a value from a given subkey
        /// </summary>
        /// <param name="registryKeyRoot">Enum of the root key to delete from (e.g. HKEY_LOCAL_MACHINE = LocalMachine)</param>
        /// <param name="subKey">Path of the subkey to delete the value from</param>
        /// <param name="value">Value to be deleted</param>
        /// <param name="registryVersion">Version of the registry to delete from. Can be 32-Bit, 64-Bit, or both</param>
        public void DeleteValue(RegistryKeyRoot registryKeyRoot, string subKey, string value, RegistryVersion registryVersion)
        {
            RegistryKey  rk;
            RegistryHive rh;
            RegistryView rv;
            RegistryKey  sk;

            switch (registryVersion)
            {
            case RegistryVersion.Both:
                rh = DetermineRegistryHive(registryKeyRoot);
                rv = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk = RegistryKey.OpenBaseKey(rh, rv);
                try
                {
                    sk = rk.OpenSubKey(subKey, true);
                    sk.DeleteValue(value, true);
                }
                catch (UnauthorizedAccessException e)
                {
                    throw new UnauthorizedAccessException("You do not have permission to write to this key." +
                                                          "Try running as administrator.", e);
                }

                rk = DetermineRootKey(registryKeyRoot);
                try
                {
                    sk = rk.OpenSubKey(subKey, true);
                    sk.DeleteValue(value, true);
                }
                catch (UnauthorizedAccessException e)
                {
                    throw new UnauthorizedAccessException(UnauthorizedAccessMsg, e);
                }

                break;

            case RegistryVersion.Only32Bit:
                rh = DetermineRegistryHive(registryKeyRoot);
                rv = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk = RegistryKey.OpenBaseKey(rh, rv);
                try
                {
                    sk = rk.OpenSubKey(subKey, true);
                    sk.DeleteValue(value, true);
                }
                catch (UnauthorizedAccessException e)
                {
                    throw new UnauthorizedAccessException(UnauthorizedAccessMsg, e);
                }
                break;

            default:
                rk = DetermineRootKey(registryKeyRoot);
                try
                {
                    sk = rk.OpenSubKey(subKey, true);
                    sk.DeleteValue(value, true);
                }
                catch (UnauthorizedAccessException e)
                {
                    throw new UnauthorizedAccessException(UnauthorizedAccessMsg, e);
                }
                break;
            }
            rk.Flush();
        }
        /// <summary>
        /// Deletes a given subkey
        /// </summary>
        /// <param name="registryKeyRoot">Enum of the root key to delete from (e.g. HKEY_LOCAL_MACHINE = LocalMachine)</param>
        /// <param name="subKey">Path of the subkey to be deleted</param>
        /// <param name="registryVersion">Version of the registry to delete from. Can be 32-Bit, 64-Bit, or both</param>
        /// <param name="forceSubKeyTreeDeletion">Can be used to force deletion of subkey tree. Defaults to false</param>
        public void DeleteSubKey(RegistryKeyRoot registryKeyRoot, string subKey, RegistryVersion registryVersion, [Optional] bool forceSubKeyTreeDeletion)
        {
            RegistryKey  rk;
            RegistryHive rh;
            RegistryView rv;

            switch (registryVersion)
            {
            case RegistryVersion.Both:
                rh = DetermineRegistryHive(registryKeyRoot);
                rv = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk = RegistryKey.OpenBaseKey(rh, rv);
                try
                {
                    rk.DeleteSubKey(subKey);
                }
                catch (NullReferenceException e)
                {
                    throw new NullReferenceException(NullRefMsg, e);
                }
                catch (InvalidOperationException e)
                {
                    if (forceSubKeyTreeDeletion)
                    {
                        DeleteSubKeyTree(registryKeyRoot, subKey, registryVersion);
                    }
                    else
                    {
                        throw new InvalidOperationException(InvalidOpMsg, e);
                    }
                }

                rk = DetermineRootKey(registryKeyRoot);
                try
                {
                    rk.DeleteSubKey(subKey);
                }
                catch (NullReferenceException e)
                {
                    throw new NullReferenceException(NullRefMsg, e);
                }
                catch (InvalidOperationException e)
                {
                    if (forceSubKeyTreeDeletion)
                    {
                        DeleteSubKeyTree(registryKeyRoot, subKey, registryVersion);
                    }
                    else
                    {
                        throw new InvalidOperationException(InvalidOpMsg, e);
                    }
                }

                break;

            case RegistryVersion.Only32Bit:
                rh = DetermineRegistryHive(registryKeyRoot);
                rv = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk = RegistryKey.OpenBaseKey(rh, rv);
                try
                {
                    rk.DeleteSubKey(subKey);
                }
                catch (NullReferenceException e) { throw new NullReferenceException(NullRefMsg, e); }
                catch (InvalidOperationException e)
                {
                    if (forceSubKeyTreeDeletion)
                    {
                        DeleteSubKeyTree(registryKeyRoot, subKey, registryVersion);
                    }
                    else
                    {
                        throw new InvalidOperationException(InvalidOpMsg, e);
                    }
                }
                break;

            default:
                rk = DetermineRootKey(registryKeyRoot);
                try
                {
                    rk.DeleteSubKey(subKey);
                }
                catch (NullReferenceException e)
                {
                    throw new NullReferenceException(NullRefMsg, e);
                }
                catch (InvalidOperationException e)
                {
                    if (forceSubKeyTreeDeletion)
                    {
                        DeleteSubKeyTree(registryKeyRoot, subKey, registryVersion);
                    }
                    else
                    {
                        throw new InvalidOperationException(InvalidOpMsg, e);
                    }
                }
                break;
            }
            rk.Flush();
        }
        /// <summary>
        /// Writes a subkey to a given key
        /// </summary>
        /// <param name="registryKeyRoot">Enum of the root key to read from (e.g. HKEY_LOCAL_MACHINE = LocalMachine)</param>
        /// <param name="subKey">Path of the subkey to be written to. Allows for nested subkeys to be written even if parts of the path
        /// do not already exist.</param>
        /// <param name="registryVersion">Version of the registry to write to. Can be 32-Bit, 64-Bit, or both</param>
        /// <param name="valuesToWrite">Values to be written to the given subkey</param>
        public void WriteSubKey(RegistryKeyRoot registryKeyRoot, string subKey,
                                RegistryVersion registryVersion, [Optional] List <KeyValuePair <string, object> > valuesToWrite)
        {
            RegistryKey  rk;
            RegistryHive rh;
            RegistryView rv;
            RegistryKey  newSk;

            switch (registryVersion)
            {
            case RegistryVersion.Both:
                rh    = DetermineRegistryHive(registryKeyRoot);
                rv    = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk    = RegistryKey.OpenBaseKey(rh, rv);
                newSk = rk.CreateSubKey(subKey);
                if (valuesToWrite != null)
                {
                    foreach (var item in valuesToWrite)
                    {
                        newSk.SetValue(item.Key, item.Value);
                    }
                }
                rk    = DetermineRootKey(registryKeyRoot);
                newSk = rk.CreateSubKey(subKey);

                if (valuesToWrite != null)
                {
                    foreach (var item in valuesToWrite)
                    {
                        newSk.SetValue(item.Key, item.Value);
                    }
                }
                break;

            case RegistryVersion.Only32Bit:
                rh    = DetermineRegistryHive(registryKeyRoot);
                rv    = DetermineRegistryView(RegistryVersion.Only32Bit);
                rk    = RegistryKey.OpenBaseKey(rh, rv);
                newSk = rk.CreateSubKey(subKey);
                if (valuesToWrite != null)
                {
                    foreach (var item in valuesToWrite)
                    {
                        newSk.SetValue(item.Key, item.Value);
                    }
                }
                break;

            default:
                rk    = DetermineRootKey(registryKeyRoot);
                newSk = rk.CreateSubKey(subKey);
                if (valuesToWrite != null)
                {
                    foreach (var item in valuesToWrite)
                    {
                        newSk.SetValue(item.Key, item.Value);
                    }
                }
                break;
            }
            rk.Flush();
        }