using Microsoft.Win32; namespace MeloongCore; public static class RegistryUtils { /// 在注册表中表示 null 的标记字符串。 public const string NULL_STRING = "__NULL__"; /// /// 读取注册表键。 /// 若键值为 ,则返回 null。 /// public static (object? result, bool exists) Read(string keyPath) { var (hive, subKeyPath, valueName) = ParsePath(keyPath); using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default); using RegistryKey? subKey = baseKey.OpenSubKey(subKeyPath); var result = subKey?.GetValue(valueName); if (result is null) return (null, false); return (result is string str && str == NULL_STRING ? null : result, true); } /// /// 读取注册表键,若该键不存在或发生异常则返回 。 /// 若键值为 ,则返回 null。 /// public static object? TryRead(string keyPath, object? defaultValue = null) { try { var (result, exists) = Read(keyPath); return exists ? result : defaultValue; } catch (Exception ex) { Logger.Warn(ex, $"读取注册表键失败({keyPath})"); return defaultValue; } } /// /// 写入注册表键。 /// 会自动创建对应的子键。 /// 若 为 null,则写入 。 /// public static void Write(string keyPath, object? value) { var (hive, subKeyPath, valueName) = ParsePath(keyPath); using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default); using RegistryKey subKey = baseKey.CreateSubKey(subKeyPath); subKey.SetValue(valueName, value ?? NULL_STRING); } /// /// 判断对应的注册表键是否存在。 /// public static bool Has(string keyPath) { var (hive, subKeyPath, valueName) = ParsePath(keyPath); using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default); using RegistryKey? subKey = baseKey.OpenSubKey(subKeyPath); if (subKey is null) return false; object notFound = new(); return !ReferenceEquals(subKey.GetValue(valueName, notFound), notFound); } /// /// 删除注册表键。若不存在则不执行操作。 /// public static void Delete(string keyPath) { var (hive, subKeyPath, valueName) = ParsePath(keyPath); using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default); using RegistryKey? subKey = baseKey.OpenSubKey(subKeyPath, writable: true); subKey?.DeleteValue(valueName, throwOnMissingValue: false); } private static (RegistryHive Hive, string SubKeyPath, string ValueName) ParsePath(string fullPath) { int hiveEnd = fullPath.IndexOf('\\'); int valueStart = fullPath.LastIndexOf('\\'); if (hiveEnd <= 0 || hiveEnd > valueStart) throw new ArgumentException($"注册表路径不完整({fullPath})", nameof(fullPath)); RegistryHive hive = fullPath.Substring(0, hiveEnd).ToUpperInvariant() switch { "HKEY_CLASSES_ROOT" => RegistryHive.ClassesRoot, "HKEY_CURRENT_USER" => RegistryHive.CurrentUser, "HKEY_LOCAL_MACHINE" => RegistryHive.LocalMachine, "HKEY_USERS" => RegistryHive.Users, "HKEY_CURRENT_CONFIG" => RegistryHive.CurrentConfig, _ => throw new ArgumentException($"注册表路径有误({fullPath})", nameof(fullPath)) }; string subKeyPath = valueStart == hiveEnd ? "" : fullPath.Substring(hiveEnd + 1, valueStart - hiveEnd - 1); return (hive, subKeyPath, fullPath.Substring(valueStart + 1)); } }