Login


Accessing the Windows Registry

By Jonathan Wood on 4/21/2014
Language: C#
Technology: .NETWinForms
Platform: Windows
License: CPOL
Views: 8,128
Frameworks & Libraries » WinForms » General » Accessing the Windows Registry

Screenshot of Sample Project

Download Sample Code Download Sample Code

Introduction

The Windows registry is a database that Windows and Windows applications use to store various settings and data. At one time, it was the recommended place to store your application's settings. However, as the Windows registry has grown and grown, storing your settings in the registry is no longer encouraged.

.NET provides tools to store your settings an XML file, and to be able to easily access those settings in a type-safe way from code. This is currently the recommended way to save application settings in your .NET applications. And there are good reasons to use this new mechanism.

However, there still remains some advantages to storing your settings in the registry. For example, you can move your application around or have different builds of your application and they can all share the same settings on a given computer.

Accessing the Registry

Of course, storing application settings isn't the only reason you might want to access the registry. You can also access and modify many Windows settings through the registry.

The registry can be accessed using the Registry class in .NET as shown in Listing 1. This code creates a subkey called "MySubKey" under the HKEY_CURRENT_USER section of the registry. If this subkey already exists, then the existing key is opened. The code then writes a string value to a setting called "Setting1" and then reads it back. The code is wrapped in a using statement to ensure that the key.Close() method always gets called at the end of the block, even if an exception causes the code to exit prematurely.

Listing 1: Accessing the Registry from .NET

using (RegistryKey key = Registry.CurrentUser.CreateSubKey("MySubKey"))
{
    // Write a value
    key.SetValue("Setting1", "Here is my string value");
    // Read a value
    object value = key.GetValue("Setting1");
}

If you only want to open the subkey for reading, then use OpenSubKey() instead of CreateSubKey(). OpenSubKey() returns null if the named subkey does not exist.

Listing 2 shows a more significant example of accessing the registry. This code lists all the settings under the main registry hives (HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, and HKEY_CURRENT_CONFIG).

Listing 2: Displaying the Values from the Primary Registry Hives

void ListRegistrySettings()
{
    ListSubkeys(Registry.ClassesRoot);
    ListSubkeys(Registry.CurrentUser);
    ListSubkeys(Registry.LocalMachine);
    ListSubkeys(Registry.Users);
    ListSubkeys(Registry.CurrentConfig);
}

void ListSubkeys(RegistryKey key, int maxItems = 50)
{
    using (key)
    {
        Console.WriteLine("Subkeys of {0}", key.Name);
        Console.WriteLine(new string('-', 45));

        foreach (string name in key.GetSubKeyNames().Take(maxItems))
            Console.WriteLine(name);
            onsole.WriteLine();
    }
}

Storing Application Settings

So, now that we've accessed the registry, let's look at how we'd store our application settings there.

Applications that store their settings in the Windows registry generally store them at HKEY_CURRENT_USER\Software\MyCompany\MyApplication, where MyCompany is the name of the application's author and MyApplication is the name of the application. Listing 3 shows a variation of Listing 1 that creates a subkey for a particular application.

Listing 3: Creating a Subkey for a Particular Application

using (RegistryKey key = Registry.CurrentUser.CreateSubKey("Software\\MyCompany\\MyApplication"))
{
    // Write a value
    key.SetValue("Setting1", "Here is my string value");
    // Read a value
    object value = key.GetValue("Setting1");
}

A Sample Application

Now that I've presented an introduction to accessing the registry, I want to present some sample code for storing your application settings to the registry.

The RegistrySettings class is shown in Listing 4. This class is an abstract class. You can create your own application settings class and have it derive from RegistrySettings. The SaveSettings() and LoadSettings() methods will then save and load all the properties in your derived class.

RegistrySettings uses reflection to find all the public properties in the class. This makes it very easy to implement. Simply declare your settings as public properties in your derived class, and the base class will find them. The data types supported are System.SByte, System.Byte, System.Int16, System.UInt16, System.Int32, System.UInt32, System.Int64, System.UInt64, System.String, System.Byte[], and System.String[] (and their aliases). Any other data type will raise an exception.

The derived class must also declare a constructor that passes two arguments to the base class: companyName and applicationName. As you might guess, these arguments are used to construct the subkey path in the registry.

Listing 4: The RegistrySettings Class

/// <summary>
/// Class for storing applications settings, which can be saved to and read back from
/// the Windows registry.
/// 
/// To use, derive your own settings class from this one. Add public properties to
/// store your settings. Then call SaveSettings() and LoadSettings() to save your
/// settings and read those settings back from the Windows registry.
/// 
/// Data types supported in your derived class include all 8, 16, 32, and 64-bit signed
/// and unsigned integer values, byte arrays, strings, and string arrays. Any other
/// data types will raise an exception.
/// </summary>
public abstract class RegistrySettings
{
    private static HashSet<string> SupportedTypes = new HashSet<string>
    {
        "System.SByte",
        "System.Byte",
        "System.Int16",
        "System.UInt16",
        "System.Int32",
        "System.UInt32",
        "System.Int64",
        "System.UInt64",
        "System.String",
        "System.Byte[]",
        "System.String[]"
    };

    private string SubkeyPath;

    public RegistrySettings(string companyName, string applicationName)
    {
        SubkeyPath = String.Format("Software\\{0}\\{1}", companyName, applicationName);
    }

    /// <summary>
    /// Saves settings to the Windows registry.
    /// </summary>
    public void SaveSettings()
    {
        using (RegistryKey key = Registry.CurrentUser.CreateSubKey(SubkeyPath))
        {
            // Iterate through all public properties
            foreach (PropertyInfo prop in GetType().GetProperties(
                BindingFlags.Instance | BindingFlags.Public))
            {
                var value = prop.GetValue(this);
                if (value != null)
                {
                    if (SupportedTypes.Contains(prop.PropertyType.ToString()))
                        key.SetValue(prop.Name, value);
                    else
                        throw new Exception(
                            String.Format("Settings property {0} has an unsupported data type ({1})",
                            prop.Name, prop.PropertyType.ToString()));
                }
            }
        }
    }

    /// <summary>
    /// Loads settings from the Windows registry.
    /// </summary>
    public void LoadSettings()
    {
        using (RegistryKey key = Registry.CurrentUser.OpenSubKey(SubkeyPath))
        {
            if (key != null)
            {
                // Iterate through all subkeys in registry
                foreach (string subkeyName in key.GetValueNames())
                {
                    PropertyInfo prop = GetType().GetProperty(subkeyName);
                    if (SupportedTypes.Contains(prop.PropertyType.ToString()))
                        prop.SetValue(this, Convert.ChangeType(key.GetValue(subkeyName),
                            prop.PropertyType));
                }
            }
        }
    }
}

The download link at the top of this article is a sample application that uses the RegistrySettings class.

Values Stored as Strings

If you inspect the registry after using the RegistrySettings class to store your settings, you might be surprised to find that many of the values are stored as strings. Only System.Int32 values will be stored as a number.

I'm not sure exactly why it's done this way but it appears to have something to do with making the Registry class more generic and able work with different value types.

The RegistryKey.SetValue() method has an override that takes a RegistryValueKind argument. When I initially wrote the RegistrySettings class, I used the RegistryValueKind argument to explicitly specify how settings were stored in the registry. However, I found the implementation to be a bit buggy. For example, if I set the type to RegistryValueKind.DWord, there was a conversion error if my value was UInt32.MaxValue.

Even though a DWORD is able to hold UInt32.MaxValue, the Registry class requires me to first safely (without throwing an exception) convert the value to an unsigned value.

There were several workarounds for this but, in order to keep the amount of code small, I stopped being explicit and just allowed the Registry class to handle things in it's own way.

Conclusion

There are many reasons why an application might want to access the Windows registry, and one of them is to store its own settings. These days, there are a lot of choices for where your application stores its settings. I hope you find this article useful if you decide to store them in the registry.

End-User License

Use of this article and any related source code or other files is governed by the terms and conditions of The Code Project Open License.

Author Information

Jonathan Wood

I'm a software/website developer working out of the greater Salt Lake City area in Utah. I've developed many websites including Black Belt Coder, Insider Articles, and others.