RegistryUtils.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  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? TryRead(string keyPath, object? defaultValue = null) {
  23. try {
  24. var (result, exists) = Read(keyPath);
  25. return exists ? result : defaultValue;
  26. } catch (Exception ex) {
  27. Logger.Warn(ex, $"读取注册表键失败({keyPath})");
  28. return defaultValue;
  29. }
  30. }
  31. /// <summary>
  32. /// 写入注册表键。
  33. /// <para/>会自动创建对应的子键。
  34. /// <para/>若 <paramref name="value"/> 为 <c>null</c>,则写入 <see cref="NULL_STRING"/>。
  35. /// </summary>
  36. public static void Write(string keyPath, object? value) {
  37. var (hive, subKeyPath, valueName) = ParsePath(keyPath);
  38. using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default);
  39. using RegistryKey subKey = baseKey.CreateSubKey(subKeyPath);
  40. subKey.SetValue(valueName, value ?? NULL_STRING);
  41. }
  42. /// <summary>
  43. /// 判断对应的注册表键是否存在。
  44. /// </summary>
  45. public static bool Has(string keyPath) {
  46. var (hive, subKeyPath, valueName) = ParsePath(keyPath);
  47. using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default);
  48. using RegistryKey? subKey = baseKey.OpenSubKey(subKeyPath);
  49. if (subKey is null) return false;
  50. object notFound = new();
  51. return !ReferenceEquals(subKey.GetValue(valueName, notFound), notFound);
  52. }
  53. /// <summary>
  54. /// 删除注册表键。若不存在则不执行操作。
  55. /// </summary>
  56. public static void Delete(string keyPath) {
  57. var (hive, subKeyPath, valueName) = ParsePath(keyPath);
  58. using RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default);
  59. using RegistryKey? subKey = baseKey.OpenSubKey(subKeyPath, writable: true);
  60. subKey?.DeleteValue(valueName, throwOnMissingValue: false);
  61. }
  62. private static (RegistryHive Hive, string SubKeyPath, string ValueName) ParsePath(string fullPath) {
  63. int hiveEnd = fullPath.IndexOf('\\');
  64. int valueStart = fullPath.LastIndexOf('\\');
  65. if (hiveEnd <= 0 || hiveEnd > valueStart) throw new ArgumentException($"注册表路径不完整({fullPath})", nameof(fullPath));
  66. RegistryHive hive = fullPath.Substring(0, hiveEnd).ToUpperInvariant() switch {
  67. "HKEY_CLASSES_ROOT" => RegistryHive.ClassesRoot,
  68. "HKEY_CURRENT_USER" => RegistryHive.CurrentUser,
  69. "HKEY_LOCAL_MACHINE" => RegistryHive.LocalMachine,
  70. "HKEY_USERS" => RegistryHive.Users,
  71. "HKEY_CURRENT_CONFIG" => RegistryHive.CurrentConfig,
  72. _ => throw new ArgumentException($"注册表路径有误({fullPath})", nameof(fullPath))
  73. };
  74. string subKeyPath = valueStart == hiveEnd ? "" : fullPath.Substring(hiveEnd + 1, valueStart - hiveEnd - 1);
  75. return (hive, subKeyPath, fullPath.Substring(valueStart + 1));
  76. }
  77. }