C# 注册表操作类

推荐图书
《C# 开发实战1200例》当年就是靠着这本书入门,非常实用【优惠券】


csharp 复制代码
using Microsoft.Win32;
using System;
using System.Security;

public class RegistryHelper
{
    // 注册表根键枚举
    public enum RegistryRootKey
    {
        ClassesRoot,
        CurrentUser,
        LocalMachine,
        Users,
        CurrentConfig
    }

    private readonly RegistryKey _rootKey;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="rootKey">要操作的注册表根键</param>
    public RegistryHelper(RegistryRootKey rootKey)
    {
        _rootKey = GetRootKey(rootKey);
    }

    /// <summary>
    /// 将枚举转换为实际的RegistryKey对象
    /// </summary>
    private RegistryKey GetRootKey(RegistryRootKey rootKey)
    {
        return rootKey switch
        {
            RegistryRootKey.ClassesRoot => Registry.ClassesRoot,
            RegistryRootKey.CurrentUser => Registry.CurrentUser,
            RegistryRootKey.LocalMachine => Registry.LocalMachine,
            RegistryRootKey.Users => Registry.Users,
            RegistryRootKey.CurrentConfig => Registry.CurrentConfig,
            _ => throw new ArgumentException("Invalid root key")
        };
    }

    /// <summary>
    /// 读取注册表值
    /// </summary>
    /// <param name="subKeyPath">子键路径</param>
    /// <param name="valueName">值名称</param>
    /// <returns>读取到的值,如果不存在返回null</returns>
    public object ReadValue(string subKeyPath, string valueName)
    {
        try
        {
            using RegistryKey? subKey = _rootKey.OpenSubKey(subKeyPath);
            return subKey?.GetValue(valueName);
        }
        catch (SecurityException ex)
        {
            throw new SecurityException("访问注册表需要管理员权限", ex);
        }
        catch (UnauthorizedAccessException ex)
        {
            throw new UnauthorizedAccessException("无权访问注册表项", ex);
        }
    }

    /// <summary>
    /// 写入注册表值
    /// </summary>
    /// <param name="subKeyPath">子键路径</param>
    /// <param name="valueName">值名称</param>
    /// <param name="value">要写入的值</param>
    /// <param name="valueKind">值的类型</param>
    public void WriteValue(string subKeyPath, string valueName, object value, RegistryValueKind valueKind)
    {
        try
        {
            using RegistryKey subKey = _rootKey.CreateSubKey(subKeyPath, true);
            subKey.SetValue(valueName, value, valueKind);
        }
        catch (SecurityException ex)
        {
            throw new SecurityException("写入注册表需要管理员权限", ex);
        }
        catch (UnauthorizedAccessException ex)
        {
            throw new UnauthorizedAccessException("无权写入注册表项", ex);
        }
    }

    /// <summary>
    /// 删除注册表值
    /// </summary>
    /// <param name="subKeyPath">子键路径</param>
    /// <param name="valueName">要删除的值名称</param>
    public void DeleteValue(string subKeyPath, string valueName)
    {
        try
        {
            using RegistryKey? subKey = _rootKey.OpenSubKey(subKeyPath, true);
            subKey?.DeleteValue(valueName, false);
        }
        catch (ArgumentException ex)
        {
            throw new ArgumentException("指定的值不存在", ex);
        }
        catch (SecurityException ex)
        {
            throw new SecurityException("删除注册表值需要管理员权限", ex);
        }
    }

    /// <summary>
    /// 检查子键是否存在
    /// </summary>
    public bool SubKeyExists(string subKeyPath)
    {
        using RegistryKey? subKey = _rootKey.OpenSubKey(subKeyPath);
        return subKey != null;
    }

    /// <summary>
    /// 创建子键
    /// </summary>
    public void CreateSubKey(string subKeyPath)
    {
        try
        {
            _rootKey.CreateSubKey(subKeyPath)?.Dispose();
        }
        catch (SecurityException ex)
        {
            throw new SecurityException("创建子键需要管理员权限", ex);
        }
    }

    /// <summary>
    /// 删除子键(递归删除所有子项)
    /// </summary>
    public void DeleteSubKey(string subKeyPath)
    {
        try
        {
            _rootKey.DeleteSubKeyTree(subKeyPath);
        }
        catch (SecurityException ex)
        {
            throw new SecurityException("删除子键需要管理员权限", ex);
        }
    }

    /// <summary>
    /// 释放资源
    /// </summary>
    public void Dispose()
    {
        _rootKey.Dispose();
        GC.SuppressFinalize(this);
    }
}

使用示例:

csharp 复制代码
class Program
{
    static void Main()
    {
        try
        {
            // 初始化操作CurrentUser下的注册表项
            var helper = new RegistryHelper(RegistryHelper.RegistryRootKey.CurrentUser);

            const string testSubKey = @"Software\RegistryHelperTest";
            const string valueName = "TestValue";

            // 创建测试子键
            if (!helper.SubKeyExists(testSubKey))
            {
                helper.CreateSubKey(testSubKey);
            }

            // 写入测试值
            helper.WriteValue(testSubKey, valueName, 12345, RegistryValueKind.DWord);

            // 读取测试值
            var value = helper.ReadValue(testSubKey, valueName);
            Console.WriteLine($"读取到的值: {value}");

            // 删除测试值
            helper.DeleteValue(testSubKey, valueName);

            // 删除测试子键
            helper.DeleteSubKey(testSubKey);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"操作失败: {ex.Message}");
        }
    }
}

重要说明:

  1. 权限要求:

    • 操作HKEY_LOCAL_MACHINE需要管理员权限
    • 在Visual Studio中运行时需要以管理员身份启动
    • 打包程序时需要设置管理员权限清单
  2. 注册表类型对照:

    csharp 复制代码
    RegistryValueKind.String     // 字符串
    RegistryValueKind.DWord      // 32位整数
    RegistryValueKind.QWord      // 64位整数
    RegistryValueKind.Binary     // 二进制数据
    RegistryValueKind.MultiString // 字符串数组
  3. 异常处理:

    • SecurityException:权限不足
    • UnauthorizedAccessException:访问被拒绝
    • ArgumentException:参数错误
    • 建议在使用时进行try-catch处理
  4. 路径规范:

    • 使用反斜杠分隔路径,例如:@"Software\MyCompany\MyApp"
    • 不要包含根键名称(例如不要写HKEY_CURRENT_USER...)
  5. 资源管理:

    • 类实现了IDisposable接口
    • 长期使用时建议使用using语句
    csharp 复制代码
    using (var helper = new RegistryHelper(...))
    {
        // 操作代码
    }

注意事项:

  • 修改注册表可能影响系统稳定性,操作前建议备份注册表
  • 生产代码中建议添加更详细的日志记录
  • 对于关键系统位置(如系统服务相关项),建议使用Windows API代替直接注册表操作
  • 32/64位系统注册表重定向问题需要注意(可通过使用RegistryView枚举处理)
相关推荐
死磕音视频2 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
顽疲5 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog5 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
曹牧5 小时前
C#:输入的字符串格式不正确
c#
程序喵大人7 小时前
【C++入门】编译链接模型 - 07 链接器怎样把符号对上号
开发语言·c++·编译器·编译链接·链接器
微三云 - 廖会灵 (私域系统开发)7 小时前
供应链系统实战:多渠道订单聚合与分布式库存一致性方案总结
开发语言·分布式·php
学逆向的7 小时前
C 数据溢出与精度丢失
c语言·开发语言·网络安全
霸道流氓气质8 小时前
AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
java·开发语言
释厄6239 小时前
错误无误公理——错误正确本同源都迭代定律——逆转有价值
android·开发语言·kotlin
2601_962885729 小时前
如何用 Python计算 CR能量指标(中间意愿指标)?
开发语言·python