2
0

RegistryUtils.cs 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. using Microsoft.Win32;
  2. namespace MeloongCore;
  3. public static class RegistryUtils {
  4. /// <summary>在注册表中表示 <c>null</c> 的标记字符串。</summary>
  5. public const string NULL_STRING = "__NULL__";
  6. /// <summary>
  7. /// 读取注册表键。
  8. /// <para/>若键值为 <see cref="NULL_STRING"/>,则返回 <c>null</c>。
  9. /// </summary>
  10. public static (object? result, bool exists) Read(string keyPath) {
  11. var (hive, subKeyPath, valueName) = ParsePath(keyPath);
  12. using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default);
  13. using RegistryKey? subKey = baseKey.OpenSubKey(subKeyPath);
  14. var result = subKey?.GetValue(valueName);
  15. if (result is null) return (null, false);
  16. return (result is string str && str == NULL_STRING ? null : result, true);
  17. }
  18. /// <summary>
  19. /// 读取注册表键,若该键不存在则返回 <paramref name="defaultValue"/>。
  20. /// <para/>若键值为 <see cref="NULL_STRING"/>,则返回 <c>null</c>。
  21. /// </summary>
  22. public static object? ReadOrDefault(string keyPath, object? defaultValue) {
  23. var (result, exists) = Read(keyPath);
  24. return exists ? result : defaultValue;
  25. }
  26. /// <summary>
  27. /// 写入注册表键。
  28. /// <para/>会自动创建对应的子键。
  29. /// <para/>若 <paramref name="value"/> 为 <c>null</c>,则写入 <see cref="NULL_STRING"/>。
  30. /// </summary>
  31. public static void Write(string keyPath, object? value) {
  32. var (hive, subKeyPath, valueName) = ParsePath(keyPath);
  33. using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default);
  34. using RegistryKey subKey = baseKey.CreateSubKey(subKeyPath);
  35. subKey.SetValue(valueName, value ?? NULL_STRING);
  36. }
  37. /// <summary>
  38. /// 判断对应的注册表键是否存在。
  39. /// </summary>
  40. public static bool Has(string keyPath) {
  41. var (hive, subKeyPath, valueName) = ParsePath(keyPath);
  42. using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default);
  43. using RegistryKey? subKey = baseKey.OpenSubKey(subKeyPath);
  44. if (subKey is null) return false;
  45. object notFound = new();
  46. return !ReferenceEquals(subKey.GetValue(valueName, notFound), notFound);
  47. }
  48. /// <summary>
  49. /// 删除注册表键。若不存在则不执行操作。
  50. /// </summary>
  51. public static void Delete(string keyPath) {
  52. var (hive, subKeyPath, valueName) = ParsePath(keyPath);
  53. using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default);
  54. using RegistryKey? subKey = baseKey.OpenSubKey(subKeyPath, writable: true);
  55. subKey?.DeleteValue(valueName, throwOnMissingValue: false);
  56. }
  57. private static (RegistryHive Hive, string SubKeyPath, string ValueName) ParsePath(string fullPath) {
  58. int hiveEnd = fullPath.IndexOf('\\');
  59. int valueStart = fullPath.LastIndexOf('\\');
  60. if (hiveEnd <= 0 || hiveEnd > valueStart) throw new ArgumentException($"注册表路径不完整({fullPath})", nameof(fullPath));
  61. RegistryHive hive = fullPath.Substring(0, hiveEnd).ToUpperInvariant() switch {
  62. "HKEY_CLASSES_ROOT" => RegistryHive.ClassesRoot,
  63. "HKEY_CURRENT_USER" => RegistryHive.CurrentUser,
  64. "HKEY_LOCAL_MACHINE" => RegistryHive.LocalMachine,
  65. "HKEY_USERS" => RegistryHive.Users,
  66. "HKEY_CURRENT_CONFIG" => RegistryHive.CurrentConfig,
  67. _ => throw new ArgumentException($"注册表路径有误({fullPath})", nameof(fullPath))
  68. };
  69. string subKeyPath = valueStart == hiveEnd ? "" : fullPath.Substring(hiveEnd + 1, valueStart - hiveEnd - 1);
  70. return (hive, subKeyPath, fullPath.Substring(valueStart + 1));
  71. }
  72. }