Code Focused
Storing Configuration Data in the Windows Registry Playground
Today, application settings are more likely to appear in local XML files, but the Windows Registry and its hives of key/value pairs can also be used. The good news is that interacting with the Registry is straightforward, as Tim shows you here.
Programmers today don't really get too excited about the Windows Registry. The youngest among them can't recall a time when text-based INI files were everywhere. One of the main reasons hardware companies began contemplating hard drives with terabyte storage sizes was to support the outrageous number of INI files. Microsoft's introduction of the Registry changed all that, with many vendors opting to move their configuration data into one of the Registry's many hives.
Within each of these user- or machine-specific hives, configuration values appear within a hard drive-like hierarchy known as keys, with each stop in the key path hosting zero or more named values. For example, inside of the current user hive, user-specific application values typically appear somewhere under the "Software" key path, in a path like "Software\CompanyName\ProductName." A configuration value that stores the default planet for a solar system application might be found at the following location:
- Hive: HKEY_CURRENT_USER
- Key: Software\SolarSystemCorp\PlanetTracker
- Value: DefaultPlanet
- Value Data Type: string
Although your software will be happier to see these elements kept distinct, it's common to see them merged into a full identifier format:
\\HKEY_CURRENT_USER\Software\SolarSystemCorp\PlanetTracker\DefaultPlanet
Today, application settings are more likely to appear in local XML files, but the Registry isn’t dead. The good news is that interacting with the Registry is straightforward. Consider a method that wraps up the ability to read a string value:
// ----- All code assumes: using Microsoft.Win32;
public static string ReadUserHiveRegistryString(string keyPath, string valueName)
{
}
When the Registry first appeared in Windows, 32-bit was the future. That didn't last long, and with the ongoing move to 64-bit programming, Microsoft implemented distinct Registry access points for the two platforms. When referencing the Registry, you must indicate the bit-size of the target platform:
// ----- The functionality differs by operating system.
RegistryView platformView = (Environment.Is64BitOperatingSystem ?
RegistryView.Registry64 : RegistryView.Registry32);
When requesting access to the registry, you must also indicate the target hive, one of the RegistryHive enumeration values. CurrentUser and LocalMachine are the two most common options for user-specific and workstation-specific access:
// ----- Open the HKEY_CURRENT_USER hive.
RegistryKey registryBase = RegistryKey.OpenBaseKey(
RegistryHive.CurrentUser, platformView);
if (registryBase == null)
return "";
Once the hive is open, you traverse down the key path in one big step:
// ----- Access the key path where the value resides.
RegistryKey registryEntry = registryBase.OpenSubKey(keyPath);
if (registryEntry == null)
{
registryBase.Close();
return "";
}
Finally, you’ll retrieve the specific value inside of the opened key path:
// ----- Access the value itself.
object registryValue = registryEntry.GetValue(valueName);
Like any good programmer, you should clean up after the mess you made:
// ----- Finished with the registry.
registryEntry.Close();
registryBase.Close();
The only thing left to do would be to return the retrieved value, if found:
// ----- Return the value, if found.
return (registryValue == null) ? "" : (string)registryValue;
With all kinds of applications storing their personal stuff there, the Registry can take on a Fort Knox-like quality. Be sure to wrap up all of your access requests in try/catch blocks, and respond to any security-related exceptions.
Writing values is almost the same as reading them, with nearly identical introductory code. After opening the platform-specific hive, you request access to the key path, adding an extra Boolean argument to indicate a read/write situation:
RegistryKey registryEntry = registryBase.OpenSubKey(keyPath, true);
If that request returns null, the key path doesn't yet exist, and you must establish it yourself through the CreateSubKey method:
registryEntry = registryBase.CreateSubKey(keyPath,
RegistryKeyPermissionCheck.ReadWriteSubTree);
Once you've gained access to the path, you can set any specific value by name:
registryEntry.SetValue(valueName, newValue);
Beyond strings, Registry values can also be stored as native integers (32-bit or 64-bit), plus a few other special-purpose formats. With the modern ability to store configuration data in information-rich XML files, complete with encrypted sections, placing such data in the Registry might seem a bit passé. But if your configuration needs are straightforward and you'd rather not mess with XML or even INI formats, the Registry offers a convenient location for your stuff.
About the Author
Tim Patrick has spent more than thirty years as a software architect and developer. His two most recent books on .NET development -- Start-to-Finish Visual C# 2015, and Start-to-Finish Visual Basic 2015 -- are available from http://owanipress.com. He blogs regularly at http://wellreadman.com.