/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/Core/Def/Options/LocalUserRegistryOptionPersister.cs
168 строк
6 KB
Tomáš Matoušek
Add Microsoft.CodeAnalysis.Contracts source package (#76997)
11 фев 2025, 21:45
Не верифицирован
11 фев 2025, 21:45
eeff8ea
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.Win32; namespace Microsoft.VisualStudio.LanguageServices.Options; internal sealed class LocalUserRegistryOptionPersister { /// <summary> /// An object to gate access to <see cref="_registryKey"/>. /// </summary> private readonly object _gate = new(); private readonly RegistryKey _registryKey; private LocalUserRegistryOptionPersister(RegistryKey registryKey) { _registryKey = registryKey; } public static LocalUserRegistryOptionPersister Create(ILocalRegistry4 localRegistry) { // SLocalRegistry service is free-threaded -- see https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1408594. Contract.ThrowIfFalse(ErrorHandler.Succeeded(localRegistry.GetLocalRegistryRootEx((uint)__VsLocalRegistryType.RegType_UserSettings, out var rootHandle, out var rootPath))); var handle = (__VsLocalRegistryRootHandle)rootHandle; Contract.ThrowIfTrue(string.IsNullOrEmpty(rootPath)); Contract.ThrowIfTrue(handle == __VsLocalRegistryRootHandle.RegHandle_Invalid); var root = (__VsLocalRegistryRootHandle.RegHandle_LocalMachine == handle) ? Registry.LocalMachine : Registry.CurrentUser; return new LocalUserRegistryOptionPersister(root.CreateSubKey(rootPath, RegistryKeyPermissionCheck.ReadWriteSubTree)); } public bool TryFetch(OptionKey2 optionKey, string path, string key, out object? value) { lock (_gate) { using var subKey = _registryKey.OpenSubKey(path); if (subKey == null) { value = null; return false; } // Options that are of type bool have to be serialized as integers if (optionKey.Option.Type == typeof(bool)) { value = subKey.GetValue(key, defaultValue: (bool)optionKey.Option.DefaultValue! ? 1 : 0).Equals(1); return true; } else if (optionKey.Option.Type == typeof(long)) { var untypedValue = subKey.GetValue(key, defaultValue: optionKey.Option.DefaultValue); switch (untypedValue) { case string stringValue: { // Due to a previous bug we were accidentally serializing longs as strings. // Gracefully convert those back. var suceeded = long.TryParse(stringValue, out var longValue); value = longValue; return suceeded; } case long longValue: value = longValue; return true; } } else if (optionKey.Option.Type == typeof(int)) { var untypedValue = subKey.GetValue(key, defaultValue: optionKey.Option.DefaultValue); switch (untypedValue) { case string stringValue: { // Due to a previous bug we were accidentally serializing ints as strings. // Gracefully convert those back. var suceeded = int.TryParse(stringValue, out var intValue); value = intValue; return suceeded; } case int intValue: value = intValue; return true; } } else { // Otherwise we can just store normally value = subKey.GetValue(key, defaultValue: optionKey.Option.DefaultValue); if (optionKey.Option.Type.IsEnum) { try { value = Enum.ToObject(optionKey.Option.Type, value); } catch (ArgumentException) { // the value may be out of range for the base type of the enum value = null; return false; } } return true; } } value = null; return false; } public void Persist(OptionKey2 optionKey, string path, string key, object? value) { Contract.ThrowIfNull(_registryKey); lock (_gate) { using var subKey = _registryKey.CreateSubKey(path); var optionType = optionKey.Option.Type; // Options that are of type bool have to be serialized as integers if (optionType == typeof(bool)) { Contract.ThrowIfNull(value); subKey.SetValue(key, (bool)value ? 1 : 0, RegistryValueKind.DWord); return; } if (optionType == typeof(long)) { Contract.ThrowIfNull(value); subKey.SetValue(key, value, RegistryValueKind.QWord); return; } if (optionType.IsEnum) { Contract.ThrowIfNull(value); // If the enum is larger than an int, store as a QWord if (Marshal.SizeOf(Enum.GetUnderlyingType(optionType)) > Marshal.SizeOf(typeof(int))) { subKey.SetValue(key, (long)value, RegistryValueKind.QWord); } else { subKey.SetValue(key, (int)value, RegistryValueKind.DWord); } return; } subKey.SetValue(key, value); } } }