Ошибка при попытке установить значение DWORD в реестре Windows с помощью C#

Я пишу код, который устанавливает значение в реестре Windows. когда я устанавливаю это значение вручную, оно работает так, как ожидалось; однако, когда я хочу установить значение программно, это дает ошибку. Значение, которое я хочу определить, представляет собой тип значения DWORD «4294967295». Однако, когда я определяю это в сценарии, он говорит, что DWORD не поддерживает это значение. И, тем не менее, я могу назначить это точное значение через программу, которую я использую для ручного обновления реестра.

Вот мой код:

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

person A beginner programmer    schedule 14.03.2020    source источник
comment
Привет и добро пожаловать в Stack Overflow! Я предполагаю, что, устанавливая значение вручную, вы имеете в виду, например, RegEdit.msc или подобное приложение? Из любопытства, какое приложение вы используете для ручного редактирования реестра Windows?   -  person Jeremy Caney    schedule 14.03.2020
comment
Я захожу в regedit, и программа, которую я редактирую, — это игра.   -  person A beginner programmer    schedule 14.03.2020
comment
При вызове RegistryKey.SetValue с RegistryValueKind.DWord метод пытается Convert.ToInt32() передать значение, которое вы передали. Вместо этого используйте QWord. Если вы не укажете тип и установите uint.MaxValue, будет сохранена строка.   -  person Jimi    schedule 14.03.2020
comment
@Jimi: Разве он не должен вызывать Convert.ToUInt32() внутри, поскольку DWORD — это целое число без знака? Тем не менее, если бы это было так, я бы ожидал, что код OP будет работать правильно, поскольку long со значением uint.MaxValue, очевидно, может быть преобразован в uint.   -  person Jeremy Caney    schedule 14.03.2020
comment
@Jeremy Caney RegistryKey.SetValue() вызывает Convert.ToInt32(), Int32 не long.   -  person Jimi    schedule 14.03.2020
comment
Ошибка № 24954. Registry.GetValue возвращает Int32 для REG_DWORD вместо Uint32 (может не исправить).   -  person Jimi    schedule 14.03.2020


Ответы (1)


Как вы, вероятно, знаете, DWORD — это хранится как 32-битное двоичное число. Что может быть не сразу очевидно, так это то, что он без знака — и, следовательно, UInt32 (uint). В противном случае вы не сможете сохранить значение 4294967295, так как максимальное значение целого числа со знаком (int) равно 2 147 483 647.

Однако есть одна загвоздка! Как отметил @Jimi в комментариях, SetValue() попытается выполнить Convert.ToInt32(), что вызовет переполнение с любым значением выше Int32.MaxValue — таким образом, вы получите сообщение об ошибке. Можно было бы ожидать, что он будет использовать Convert.ToUInt32(), но, как также обнаружил @Jimi, это известная ошибка в методе, которую Microsoft не может исправить из-за проблем с обратной совместимостью.

Вместо этого метод SetValue() преобразует Int32 (int) со знаком в 32-битное двоичное число без знака, при этом значения 0…2147483647 остаются без изменений, а значения -2147483647…-1 сохраняются в диапазоне 2147483648…4294967295.

Это двоичное преобразование немного запутано, если вы думаете об этом как о целом числе со знаком. Но, к счастью, вы можете использовать встроенный в C# unchecked() ключевое слово, чтобы разрешить переполнение и эффективно обрабатывать uint как подписанное int в пределах этих диапазонов:

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

Это действительно удобно, потому что позволяет вам продолжать работать со стандартным диапазоном UInt32 (uint) 0…4294967295 точно так же, как если бы вы, например, RegEdit, не задумываясь о том, как обрабатывается двоичное преобразование.

person Jeremy Caney    schedule 14.03.2020