RegistryKey.GetValue() returns null on existing values

I encountered a very curious issue today, as a user of one of my tools complained that the tool was crashing because of an access to an uninitialized field. Because of the error reporting system in all my tools that gives the user the stack trace to pass on to me, I saw that the line that was causing the crash was a GetValue() on a registry key and value, that the user insisted existed. So, looking around StackOverflow, I noticed that if you compile to x86, you may have issues accessing some keys and values in the registry, because Windows may give you the wrong Registry view by default (I guess Windows gives a different view to 32-bit applications that the one it gives to 64-bit ones). I was accessing the keys by using OpenSubKey() on Registry.CurrentUser, but I guess that gives me whatever registry view Windows wants to give me.

So, given that there’s two RegistryViews, I thought I should change my GetRegistrySetting() and SetRegistrySetting() code to try both. Once I did, the problem was gone. Read on for the code that is part of my LeftosCommonLibrary set of tools, or just view the file that contains the code below in GitHub.

        /// <summary>The application's registry key; used by GetRegistrySetting and SetRegistrySetting for example.</summary>
        public static string AppRegistryKey = "";

        /// <summary>Sets a registry setting using the AppRegistryKey field as the key.</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="setting">The setting.</param>
        /// <param name="value">The value.</param>
        /// <exception cref="System.Exception">KeyCreateError: Thrown if the key could neither be opened nor created.</exception>
        public static void SetRegistrySetting<T>(string setting, T value)
        {
            SetRegistrySetting(AppRegistryKey, setting, value);
        }

        /// <summary>Sets a registry setting using a user-defined key.</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">The key.</param>
        /// <param name="setting">The setting.</param>
        /// <param name="value">The value.</param>
        /// <exception cref="System.Exception">KeyCreateError: Thrown if the key could neither be opened nor created.</exception>
        public static void SetRegistrySetting<T>(string key, string setting, T value)
        {
            var rk = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
            try
            {
                rk = rk.OpenSubKey(key, true);
                if (rk == null)
                {
                    rk = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32);
                    rk = rk.OpenSubKey(key, true);
                    if (rk == null)
                    {
                        throw new Exception();
                    }
                }
            }
            catch (Exception)
            {
                rk = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
                rk.CreateSubKey(key);
                rk = rk.OpenSubKey(key, true);
                if (rk == null)
                {
                    throw new Exception("KeyCreateError");
                }
            }

            rk.SetValue(setting, value);
        }

        /// <summary>Gets a registry setting using the AppRegistryKey field as the key.</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="setting">The setting.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>The registry setting's value.</returns>
        /// <exception cref="System.Exception">KeyOpenError: Thrown if the key couldn't be opened.</exception>
        public static T GetRegistrySetting<T>(string setting, T defaultValue)
        {
            return GetRegistrySetting(AppRegistryKey, setting, defaultValue);
        }

        /// <summary>Gets a registry setting using the AppRegistryKey field as the key.</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">The key.</param>
        /// <param name="setting">The setting.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>The registry setting's value.</returns>
        /// <exception cref="System.Exception">KeyOpenError: Thrown if the key couldn't be opened.</exception>
        public static T GetRegistrySetting<T>(string key, string setting, T defaultValue)
        {
            var settingValue = defaultValue;
            try
            {
                var rk = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
                rk = rk.OpenSubKey(key);
                if (rk != null)
                {
                    settingValue = (T) (Convert.ChangeType(rk.GetValue(setting, defaultValue), typeof(T)));
                }
                else
                {
                    rk = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32);
                    rk = rk.OpenSubKey(key);
                    if (rk != null)
                    {
                        settingValue = (T) (Convert.ChangeType(rk.GetValue(setting, defaultValue), typeof(T)));
                    }
                    else
                    {
                        throw new Exception("KeyOpenError");
                    }
                }
            }
            catch (InvalidCastException)
            {
                settingValue = defaultValue;
            }
            catch (FormatException)
            {
                settingValue = defaultValue;
            }

            return settingValue;
        }
Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s