Search code examples
c#.netregistryuint32dword

Error when trying to set a DWORD value in the windows registry using C #


I'm writing code that sets a value in the Windows registry. when I set that value manually, it works as expected; when I want to set the value programmatically, however, it gives an error. The value I want to define is a DWORD value type that is "4294967295". When I define that in the script, though, it says that DWORD does not support this value. And, yet, I can assign that exact value via the program I am using to manually update the registry.

Here's my code:

RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Lost in Days Studio\NO TIME", true);
key.SetValue("Current", 4294967295, RegistryValueKind.DWord);
key.Close();

Solution

  • As you likely know, a DWORD is stored as a 32 bit binary number. What may not be immediately obvious, though, is that it's unsigned—and, thus, a UInt32 (uint). Otherwise, you wouldn't be able to store a value of 4294967295, since the maximum value for a signed integer (int) is 2,147,483,647.

    There's a catch, however! As @Jimi noted in the comments, SetValue() will attempt to do a Convert.ToInt32(), which will cause an overflow with any value above Int32.MaxValue—thus the error you are receiving. One would expect it to use Convert.ToUInt32() but, as @Jimi also discovered, that is a known bug in the method, which Microsoft is unable to fix due to backward compatibility concerns.

    Instead, the SetValue() method converts a signed Int32 (int) into an unsigned 32 bit binary number, with values of 0…2147483647 remaining as is, but values of -2147483647…-1 getting saved to the 2147483648…4294967295 range.

    That binary conversion is a bit convoluted if you're thinking about this as a signed integer. But, fortunately, you can use C#’s built-in unchecked() keyword to permit the overflow and effectively treat your uint as a signed int within those ranges:

    key.SetValue("Current", unchecked((int)4294967295), RegistryValueKind.DWord);
    

    This is really handy because it allows for you to continue to work with a standard UInt32 (uint) range of 0…4294967295, exactly like you would via e.g. RegEdit, without having to think about how the binary conversion is being handled.