必须以管理员权限运行才能写入HKEY_LOCAL_macHINE;OpenSubKey需显式指定writable:true;注意WOW64重定向及值类型匹配,否则静默失败或读取异常。

用 microsoft.win32.Registry 读写本地注册表必须以管理员权限运行
windows 对 HKEY_LOCAL_MACHINE(尤其是 SOFTWARE、SYSTEM)有严格写入限制。即使代码语法正确,RegistryKey.SetValue() 也会静默失败或抛出 UnauthorizedaccessException。这不是 .NET 的 bug,而是 UAC 机制在起作用。
实操建议:
- 开发阶段右键 VS 或终端 → “以管理员身份运行”
- 发布时在
app.manifest中设置requestedExecutionLevel level="requireAdministrator" - 只读操作(如查
HKEY_CURRENT_USER)通常无需提权 - 避免硬编码路径,用
Registry.LocalMachine或Registry.CurrentUser静态实例更安全
RegistryKey.OpenSubKey() 默认是只读,写入前必须显式指定 writable: true
这是最常被忽略的参数陷阱。以下代码看似合理,实则写入会失败:
var key = Registry.LocalMachine.OpenSubKey(@"SOFTWAREMyApp"); key.SetValue("Version", "1.2.3"); // 抛出 NotSupportedException
正确写法:
var key = Registry.LocalMachine.OpenSubKey(@"SOFTWAREMyApp", writable: true); if (key != NULL) { key.SetValue("Version", "1.2.3"); key.Close(); }
注意点:
-
OpenSubKey(path, writable: false)是默认行为,不可省略writable: true - 打开不存在的子键时,
OpenSubKey()返回null;需用CreateSubKey()创建 -
CreateSubKey()自动具备写权限,但返回值仍需判空(可能因权限/路径非法失败)
字符串值类型不只有 RegistryValueKind.String,误设会导致读取异常
注册表值有多种类型:String、Dword、QWord、Binary、ExpandString 等。C# 默认用 SetValue(name, value) 写入时类型为 String,但若目标程序期望的是 DWord(比如开关配置),就会读错。
示例:写入布尔开关应使用 DWord 类型
key.SetValue("EnableLogging", 1, RegistryValueKind.DWord); // 正确 key.SetValue("EnableLogging", "1"); // 错误:存成字符串,其他程序可能无法识别
读取时也需匹配类型:
-
key.GetValue("EnableLogging")返回Object,需手动转型 -
key.GetValueKind("EnableLogging")可检查实际存储类型 - 对
DWord值,用(int)key.GetValue("name")更安全,避免装箱异常
64 位系统上 32 位进程默认访问的是重定向视图(WOW64)
在 64 位 Windows 上,32 位 .NET 应用(如 AnyCPU + Prefer 32-bit)调用 Registry.LocalMachine 时,SOFTWARE 下的键会被自动映射到 SOFTWAREWOW6432node。这意味着你写入的位置和 64 位程序看到的位置不同。
解决方式取决于需求:
- 想让所有进程读同一位置:用
RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) - 明确适配 32 位环境:保持默认即可
- 不确定目标平台?先用
Environment.Is64BitOperatingSystem判断,再选视图
示例(强制访问原生 64 位视图):
using var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); using var key = baseKey.OpenSubKey(@"SOFTWAREMyApp", writable: true);
这个细节在部署服务或跨架构调试时极易踩坑——你以为写进去了,其实写到了镜像节点里。