public IRegistryKey CreateKey(string keyPath, RegistryKeyPermissionCheck permissionCheck = default)
        {
            IRegistryKey cleanUpKey = null;

            if (!keyPath.Contains(RegistryPathDelimiter))
            {
                throw new ArgumentException("Can not create a root key itself", nameof(keyPath));
            }
            try
            {
                IRegistryKey root        = GetCorrespondingRoot(keyPath);
                string       openKeyName = keyPath.MustEndWith(RegistryPathDelimiter).Remove(root.Name.MustEndWith(RegistryPathDelimiter));
                cleanUpKey = root;
                if (openKeyName.IsNullOrWhitespace())
                {
                    throw new ArgumentException("Can not create a root key itself", nameof(keyPath));
                }
                IRegistryKey key = root.CreateSubKey(openKeyName, permissionCheck);
                return(key);
            }
            finally
            {
                cleanUpKey?.Dispose();
            }
        }
        public IRegistryKey OpenKey(string keyPath, RegistryKeyPermissionCheck permissionCheck = default, RegistryRights rights = default)
        {
            IRegistryKey cleanUpKey = null;

            try
            {
                IRegistryKey root        = GetCorrespondingRoot(keyPath);
                string       openKeyName = keyPath.MustEndWith(RegistryPathDelimiter).Remove(root.Name.MustEndWith(RegistryPathDelimiter));
                if (openKeyName.IsNullOrWhitespace())
                {
                    return(root);
                }
                cleanUpKey = root;
                IRegistryKey key = root.OpenSubKey(openKeyName, permissionCheck, rights);
                return(key);
            }
            finally
            {
                cleanUpKey?.Dispose();
            }
        }
        /// <summary>
        /// Tries to obtaining the path to the latest version of the SQL LocalDB
        /// native API DLL for the currently executing process.
        /// </summary>
        /// <param name="fileName">
        /// When the method returns, contains the path to the SQL Local DB API
        /// to use, if found; otherwise <see langword="null"/>.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the native API path was successfully found;
        /// otherwise <see langword="false"/>.
        /// </returns>
        internal bool TryGetLocalDbApiPath(out string fileName)
        {
            fileName = null;

            string       keyName = DeriveLocalDbRegistryKey();
            IRegistryKey key     = Registry.OpenSubKey(keyName);

            if (key == null)
            {
                Logger.RegistryKeyNotFound(keyName);
                return(false);
            }

            Version latestVersion   = null;
            Version overrideVersion = null;
            string  path            = null;

            try
            {
                // Is there a setting overriding the version to load?
                string overrideVersionString = ApiVersion;

                foreach (string versionString in key.GetSubKeyNames())
                {
                    if (!Version.TryParse(versionString, out Version version))
                    {
                        Logger.InvalidRegistryKey(versionString);
                        continue;
                    }

                    if (!string.IsNullOrEmpty(overrideVersionString) &&
                        overrideVersion == null &&
                        string.Equals(versionString, overrideVersionString, StringComparison.OrdinalIgnoreCase))
                    {
                        Logger.NativeApiVersionOverriddenByUser(version);
                        overrideVersion = version;
                    }

                    if (latestVersion == null ||
                        latestVersion < version)
                    {
                        latestVersion = version;
                    }
                }

                if (!string.IsNullOrEmpty(overrideVersionString) && overrideVersion == null)
                {
                    Logger.NativeApiVersionOverrideNotFound(overrideVersionString);
                }

                Version versionToUse = overrideVersion ?? latestVersion;

                if (versionToUse != null)
                {
                    using (IRegistryKey subkey = key.OpenSubKey(versionToUse.ToString()))
                    {
                        path = subkey.GetValue("InstanceAPIPath");
                    }

                    NativeApiVersion = versionToUse;
                }
            }
            finally
            {
                key.Dispose();
            }

            if (string.IsNullOrEmpty(path))
            {
                Logger.NativeApiNotFound();
                return(false);
            }

            if (!File.Exists(path))
            {
                Logger.NativeApiLibraryNotFound(path);
                return(false);
            }

            fileName = Path.GetFullPath(path);
            return(true);
        }
        /// <summary>
        /// Tries to obtaining the path to the latest version of the SQL LocalDB
        /// native API DLL for the currently executing process.
        /// </summary>
        /// <param name="fileName">
        /// When the method returns, contains the path to the SQL Local DB API
        /// to use, if found; otherwise <see langword="null"/>.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the native API path was successfully found;
        /// otherwise <see langword="false"/>.
        /// </returns>
        internal static bool TryGetLocalDbApiPath(out string fileName)
        {
            fileName = null;

            bool isWow64Process = Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess;

            // Open the appropriate Registry key if running as a 32-bit process on a 64-bit machine
            string keyName = string.Format(
                CultureInfo.InvariantCulture,
                @"SOFTWARE\{0}Microsoft\Microsoft SQL Server Local DB\Installed Versions",
                isWow64Process ? @"Wow6432Node\" : string.Empty);

            IRegistryKey key = Registry.OpenSubKey(keyName);

            if (key == null)
            {
                Logger.Warning(Logger.TraceEvent.RegistryKeyNotFound, SR.NativeMethods_RegistryKeyNotFoundFormat, keyName);
                return(false);
            }

            Version latestVersion   = null;
            Version overrideVersion = null;
            string  path            = null;

            try
            {
                // Is there a setting overriding the version to load?
                string overrideVersionString = SqlLocalDbConfig.NativeApiOverrideVersionString;

                foreach (string versionString in key.GetSubKeyNames())
                {
                    Version version;

                    try
                    {
                        version = new Version(versionString);
                    }
                    catch (ArgumentException)
                    {
                        Logger.Warning(Logger.TraceEvent.InvalidRegistryKey, SR.NativeMethods_InvalidRegistryKeyNameFormat, versionString);
                        continue;
                    }
                    catch (FormatException)
                    {
                        Logger.Warning(Logger.TraceEvent.InvalidRegistryKey, SR.NativeMethods_InvalidRegistryKeyNameFormat, versionString);
                        continue;
                    }
                    catch (OverflowException)
                    {
                        Logger.Warning(Logger.TraceEvent.InvalidRegistryKey, SR.NativeMethods_InvalidRegistryKeyNameFormat, versionString);
                        continue;
                    }

                    if (!string.IsNullOrEmpty(overrideVersionString) &&
                        overrideVersion == null &&
                        string.Equals(versionString, overrideVersionString, StringComparison.OrdinalIgnoreCase))
                    {
                        Logger.Verbose(Logger.TraceEvent.NativeApiVersionOverriddenByUser, SR.NativeMethods_ApiVersionOverriddenByUserFormat, version);
                        overrideVersion = version;
                    }

                    if (latestVersion == null ||
                        latestVersion < version)
                    {
                        latestVersion = version;
                    }
                }

                if (!string.IsNullOrEmpty(overrideVersionString) && overrideVersion == null)
                {
                    Logger.Warning(
                        Logger.TraceEvent.NativeApiVersionOverrideNotFound,
                        SR.NativeMethods_OverrideVersionNotFoundFormat,
                        overrideVersionString,
                        Environment.MachineName,
                        latestVersion);
                }

                Version versionToUse = overrideVersion ?? latestVersion;

                if (versionToUse != null)
                {
                    using (var subkey = key.OpenSubKey(versionToUse.ToString()))
                    {
                        path = subkey.GetValue("InstanceAPIPath");
                    }

                    NativeApiVersion = versionToUse;
                }
            }
            finally
            {
                key.Dispose();
            }

            if (string.IsNullOrEmpty(path))
            {
                Logger.Warning(Logger.TraceEvent.NoNativeApiFound, SR.NativeMethods_NoNativeApiFound);
                return(false);
            }

            if (!File.Exists(path))
            {
                Logger.Error(Logger.TraceEvent.NativeApiPathNotFound, SR.NativeMethods_NativeApiNotFoundFormat, path);
                return(false);
            }

            fileName = Path.GetFullPath(path);
            return(true);
        }