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));
}
}