Search code examples
c#registry

Specified cast is not valid - Object to long


I'm working on some code that writes a DateTime value to the Windows registry and then retrieves it.

Code

RegistryKey subKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\" + Project.Properties.Resources.PRODUCT_NAME, true);

DateTime dt = DateTime.Now;
subKey.SetValue("TrialEndDate", dt.ToBinary());

DateTime dt2 = DateTime.FromBinary((long)subKey.GetValue("TrialEndDate"));

The last line throws the following exception: Specified cast is not valid

The FromBinary method expects a long parameter so I'm attempting to cast the object returned from GetValue.


Solution

  • When you use SubKey.SetValue(string, object), the value is stored as a string unless it is a 32-bit integer. From the documentation:

    Numeric types other than 32-bit integers are stored as strings by this method overload. Enumeration elements are stored as strings containing the element names.

    This present a problem, because DateTime.ToBinary produces a 64-bit integer. So it will be converted to a string for storage. When you retrieve the value you are casting instead of Converting, so it'll fail.

    If you want to store the date as a binary number, you can fix this by using the overload of SetValue that lets you specify the type. For example:

    subKey.SetValue(trialEndDate, dt.ToBinary(), RegistryValueKind.QWord);
    

    This will store the binary value as a 64-bit integer and allow you to retrieve it as the same.

    You could also choose to store the DateTime as a string (which might be more readable to someone editing the registry) and parse it using DateTime.Parse or DateTime.ParseExact. This is probably how I would do it:

    const string FORMAT = ""yyyyMMddHHmmss";
    RegistryKey subKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\" + Project.Properties.Resources.PRODUCT_NAME, true);
    var dt = DateTime.Now;
    subKey.SetValue("TrialEndDate", dt.String(FORMAT), RegistryValueKind.String);
    var storedValue = subKey.GetValue("TrialEndDate") as string;
    var dt2 = DateTime.ParseExact(storedValue, FORMAT);