Click here to Skip to main content
Click here to Skip to main content

A Small Class Providing Typed Access To The Registry

By , 28 May 2006
 

Sample Image - TypedRegistry_Image.png

Introduction

When I migrated to .NET from Borland Delphi, I felt a lack in the standard RegistryKey class. There are methods like WriteCurrency, WriteDate, and WriteBinaryData in Delphi's TRegistry class. Some useful methods working with the RegistryValueKind enumeration were added in .NET 2.0. But there is still a problem: how, for example, to save a value of the System.Decimal type in a registry key. The TypedRegistry assembly contains a class which allows to write and read data of the following types to/from a registry key: String, Byte[], Int32, Boolean, DateTime, Decimal, Double, Guid, Int64.

Though this is possible with .NET 2.0, the values are never saved using the REG_QWORD format (introduced in Windows 2000) because .NET 1.1 has no support for such a format. The TypedRegistry assembly was aimed for both .NET versions (1.1 and 2.0). So, all 8-byte values of the DateTime, Double, and Int64 types are saved as byte arrays.

AcedRegistry Class

public class AcedRegistry : IDisposable

Provides methods for writing/reading typed data to/from the registry.

public AcedRegistry(AcedRootKey registryRootKey, string registryKey, bool writable)

Opens a root registry key (such as HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE) specified by the registryRootKey parameter. Then, opens a key passed as string via the registryKey parameter. If the value of the writable parameter is false, the registry key is opened in read-only mode. If that value is true, the registry key is opened (or created, if not exists) in read-write mode.

For example, you may pass the AcedRootKey.LocalMachine value in the first parameter, and the @"Software\CompanyName\ApplicationName" string in the registryKey parameter. The following is the list of possible values for the registryRootKey parameter. Each value corresponds to an instance of the root key exposed by the Microsoft.Win32.Registry class:

  • AcedRootKey.ClassesRoot
  • AcedRootKey.CurrentConfig
  • AcedRootKey.CurrentUser
  • AcedRootKey.DynData
  • AcedRootKey.LocalMachine
  • AcedRootKey.PerformanceData
  • AcedRootKey.Users
public Microsoft.Win32.RegistryKey RegistryKey { get; }

Gets the related instance of the Microsoft.Win32.RegistryKey class. This property returns null if there is an error during opening or creating a registry key in the constructor of this class.

public void Dispose()

Closes the related registry key, and flushes it to disk if its contents have been modified.

public void Put(string valueName, String value)
public void Put(string valueName, Byte[] value)
public void Put(string valueName, Int32 value)
public void Put(string valueName, Boolean value)
public void Put(string valueName, DateTime value)
public void Put(string valueName, Decimal value)
public void Put(string valueName, Double value)
public void Put(string valueName, Guid value)
public void Put(string valueName, Int64 value)

Writes the value to the open registry key, with the value name specified by the first parameter (valueName).

public bool Get(string valueName, ref String value)
public bool Get(string valueName, ref Byte[] value)
public bool Get(string valueName, ref Int32 value)
public bool Get(string valueName, ref Boolean value)
public bool Get(string valueName, ref DateTime value)
public bool Get(string valueName, ref Decimal value)
public bool Get(string valueName, ref Double value)
public bool Get(string valueName, ref Guid value)
public bool Get(string valueName, ref Int64 value)

Reads a value of the corresponding type with the specified name (valueName) from the open registry key. It is then returned in the value parameter. The method returns true if the value was successfully read. If there is no value with such a name in the current registry key, the method returns false, and does not modify the value parameter.

public String GetDef(string valueName, String defaultValue)
public Byte[] GetDef(string valueName, Byte[] defaultValue)
public Int32 GetDef(string valueName, Int32 defaultValue)
public Boolean GetDef(string valueName, Boolean defaultValue)
public DateTime GetDef(string valueName, DateTime defaultValue)
public Decimal GetDef(string valueName, Decimal defaultValue)
public Double GetDef(string valueName, Double defaultValue)
public Guid GetDef(string valueName, Guid defaultValue)
public Int64 GetDef(string valueName, Int64 defaultValue)

Reads a value of the corresponding type with the specified name (valueName) from the open registry key, and returns that value as the method's result. If there is no value with such a name in the related registry key, the method returns a value of the defaultValue parameter.

Example of Usage

The following is a code fragment which saves and loads the program configuration as a set of values in the registry key:

private const string
    DemoRegistryKeyName = "Software\\TypedRegistryDemo",
    cfgStringValueName = "StringValue",
    cfgDateTimeValueName = "DateTimeValue",
    cfgDecimalValueName = "DecimalValue",
    cfgBooleanValueName = "BooleanValue",
    cfgEnumValueName = "EnumerationElement",
    cfgByteArrayValueName = "Image";

private static string _stringValue;
private static DateTime _dateTimeValue;
private static decimal _decimalValue;
private static bool _booleanValue;
private static MyColors _enumValue;
private static byte[] _byteArrayValue;

private static void SaveConfig()
{
    using (AcedRegistry config = 
           new AcedRegistry(AcedRootKey.CurrentUser,
                            DemoRegistryKeyName, true))
    {
        config.Put(cfgStringValueName, _stringValue);
        config.Put(cfgDateTimeValueName, _dateTimeValue);
        config.Put(cfgDecimalValueName, _decimalValue);
        config.Put(cfgBooleanValueName, _booleanValue);
        config.Put(cfgEnumValueName, (int)_enumValue);
        config.Put(cfgByteArrayValueName, _byteArrayValue);
    }
}

private static void LoadConfig()
{
    using (AcedRegistry config = new AcedRegistry(AcedRootKey.CurrentUser,
        DemoRegistryKeyName, false))
    {
        config.Get(cfgStringValueName, ref _stringValue);
        config.Get(cfgDateTimeValueName, ref _dateTimeValue);
        config.Get(cfgDecimalValueName, ref _decimalValue);
        config.Get(cfgBooleanValueName, ref _booleanValue);
        _enumValue = (MyColors)config.GetDef(cfgEnumValueName, (int)_enumValue);
        config.Get(cfgByteArrayValueName, ref _byteArrayValue);
    }
}

It is convenient to enclose all method calls which access the registry into the using statement. Thus, we can be sure that the instance of the AcedRegistry class will be disposed at the end and the related instance of the standard RegistryKey class will be closed.

We can even save a value of a custom enumeration type in the registry as a value of the System.Int32 (or maybe System.Int64) type. In the above code fragment, we cast a value of the MyColors enumeration type to int before passing it to the Put method. Then, we cast it back to the MyColors type when the value is returned from the GetDef method.

Conclusion

The described class contains several methods to work with registry data in a typed manner. This is just an add-on over the standard RegistryKey class. To access the related RegistryKey while working with this class, please use the property of the same name.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Andrey Dryazgov
Software Developer
Russian Federation Russian Federation
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralGet DWORD over 2.147.483.647memberageye28 Sep '08 - 5:56 
Hi,
thanks for your great class! It works flawless with DateTime.
When I try to read a DWORD which is larger than 2.147.483.647 (Int32 Maximum) then there are some errors:
if I use your Get function with a long -> InvalidCast
if I use it with a Int32 -> wrong value (negative number)
Could you help me?
Thanks
ageye
GeneralRe: Get DWORD over 2.147.483.647memberAndrey Dryazgov28 Sep '08 - 7:34 
Hi,
 
You may add the following code to the AcedRegistry class:
 
---------------------------------------------------------
// UInt32 values
 
public void Put(string valueName, uint value)
{
      if (_registryKey != null)
            _registryKey.SetValue(valueName, value);
}
 
public bool Get(string valueName, ref uint value)
{
      if (_registryKey != null)
      {
            object v = _registryKey.GetValue(valueName, null);
            if (v != null)
            {
                  value = (uint)v;
                  return true;
            }
      }
      return false;
}
 
public int GetDef(string valueName, uint defaultValue)
{
      if (_registryKey != null)
      {
            object v = _registryKey.GetValue(valueName, null);
            if (v != null)
                  defaultValue = (uint)v;
      }
      return defaultValue;
}
---------------------------------------------------------
 
Hopefully, using the Get(..., ref uint) method will
resolve the issue.
 
Regards,
 
-Andrey
QuestionBug in GetDef?memberRudolf Jan Heijink15 Jan '07 - 10:37 
public int GetDef(string valueName, int defaultValue)
        {
            if (_registryKey != null)
            {
                object v = _registryKey.GetValue(valueName, null);
                if (v != null)
                    defaultValue = (int)v;
            }
            return defaultValue;
        }
 
I tried to use this class. It works fine for strings, but generates a type conversion exception if I try to use it on int keys. If the key does not exist, no problem, but if it exists, defaultvalue= (int)v reports an illegal type cast.
 
I am really a C# and .NET beginner, so I do not yet understand what goes wrong. Any help for this problem would be appreciated...
 
Thanks,
AnswerRe: Bug in GetDef? [modified]memberAndrey Dryazgov15 Jan '07 - 11:13 
This method expects that data in Registry are in binary format
(a 32-bit integer value). It is not suitable for reading
numbers that are in string format. You can use this method
if the value was stored using the following method:
 
public void Put(string valueName, int value);
 
Regards,
 
-Andrey

GeneralRe: Bug in GetDef?memberRudolf Jan Heijink16 Jan '07 - 9:29 
Dear Andrey,
 
Thank you very much for your very fast reply. I think I did it just as you said:
 
Declaration:
public int MRULength=4; // number of files to display in MRU list
 
Write into the registry:
AppKey.Put("MRULength", MRULength);
 
read from the registry:
 
AppKey.GetDef("MRULength", (int)4);
 
I checked the format, using the Windows registry editor. It shows as type REG_BINARY and value 04 00 00 00 00 00 00 00
 
The reported exception says: The specified conversion is invalid (It was reported to me in Dutch, so I translated this back to English, you may see a slightly different text).
 
The variable v is a byte array, holding the requested value 4 in v[0].
 
So what can be wrong?
AnswerRe: Bug in GetDef?memberRudolf Jan Heijink26 Jan '07 - 9:23 
I really wanted to solve this problem, so I checked again. Now the registry monitor displays the Int32 registry value as DWORD. problem solved. Laugh | :laugh:
 
I really have not the faintest idea what happend and why I saw the REG_BINARY format the first time I checked. Anyway, there should be a DWORD registry entry for this method to work properly..
regards,
 
Rudolf Heijink

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 28 May 2006
Article Copyright 2006 by Andrey Dryazgov
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid