Windows 登錄表 是系統與應用程式設定的核心儲存庫。C# 透過 Microsoft.Win32.Registry 與 RegistryKey 類別提供完整的受控封裝。本文系統整理登錄表項 (Key) 與值 (Value) 的 CRUD 操作、存在性檢查、預設值處理與最佳實務。
using Microsoft.Win32;
// 根鍵對應
Registry.ClassesRoot // HKEY_CLASSES_ROOT
Registry.CurrentUser // HKEY_CURRENT_USER
Registry.LocalMachine // HKEY_LOCAL_MACHINE (需管理員權限寫入)
Registry.Users // HKEY_USERS
Registry.CurrentConfig // HKEY_CURRENT_CONFIG
// 開啟/建立子鍵 (可寫)
RegistryKey key = Registry.CurrentUser.CreateSubKey(@"Software\MyApp");
// 僅讀取
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\MyApp", writable: false);
// 使用完畢必須關閉
key?.Close();
// 或使用 using (Net Core 2.1+ RegistryKey 實作 IDisposable)
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\MyApp", true)) { ... }
// 回傳現有或新建的 RegistryKey,若存在不報錯
RegistryKey software = Registry.CurrentUser.CreateSubKey(@"Software\MyApp\Settings");
// 唯讀
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\MyApp"))
{
// 讀取值...
}
// 可寫 (第二參數 true)
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\MyApp", true))
{
// 寫入值...
}
若項不存在,OpenSubKey回傳null,不拋例外。
// 刪除空項
Registry.CurrentUser.DeleteSubKey(@"Software\MyApp\Settings");
// 刪除項及所有子項/值 (遞迴)
Registry.CurrentUser.DeleteSubKeyTree(@"Software\MyApp\Settings");
// 第二參數 throwOnMissing: true(預設) 找不到拋例外,false 不拋
Registry.CurrentUser.DeleteSubKey(@"Software\MyApp\Settings", false);
public static bool KeyExists(RegistryKey root, string subPath)
{
using (var key = root.OpenSubKey(subPath))
return key != null;
}
// 用法
bool exists = KeyExists(Registry.CurrentUser, @"Software\MyApp");
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\MyApp", true))
{
// 字串 (預設 REG_SZ)
key.SetValue("UserName", "Admin");
// 整數 (REG_DWORD)
key.SetValue("MaxConnections", 100, RegistryValueKind.DWord);
// 二進位 (REG_BINARY)
key.SetValue("BinaryData", new byte[] { 0x01, 0x02, 0x03 }, RegistryValueKind.Binary);
// 多字串 (REG_MULTI_SZ)
key.SetValue("ServerList", new string[] { "srv1", "srv2" }, RegistryValueKind.MultiString);
// 展開字串 (REG_EXPAND_SZ) - 含環境變數
key.SetValue("LogPath", "%APPDATA%\\MyApp\\Logs", RegistryValueKind.ExpandString);
// QWORD (64位整數)
key.SetValue("LargeNumber", 9223372036854775807L, RegistryValueKind.QWord);
}
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\MyApp"))
{
if (key == null) return;
// 讀取字串
string name = key.GetValue("UserName") as string ?? "Guest";
// 讀取整數 (預設 0)
int maxConn = (int)(key.GetValue("MaxConnections") ?? 0);
// 讀取二進位
byte[] bin = key.GetValue("BinaryData") as byte[];
// 讀取多字串
string[] servers = key.GetValue("ServerList") as string[];
// 讀取預設值 (名稱為 null 或空字串)
string defaultVal = key.GetValue("") as string ?? "(未設定)";
}
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\MyApp", true))
{
key.DeleteValue("UserName", false); // false: 找不到不拋例外
// 預設值無法刪除,嘗試會拋 ArgumentException
}
public static bool ValueExists(RegistryKey root, string subPath, string valueName)
{
using (var key = root.OpenSubKey(subPath))
{
if (key == null) return false;
return key.GetValue(valueName) != null;
}
}
public static class RegistryHelper
{
public static bool KeyExists(RegistryHive hive, string path)
{
using (var baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default))
using (var key = baseKey.OpenSubKey(path))
return key != null;
}
public static T GetValue(RegistryHive hive, string path, string name, T defaultValue = default)
{
using (var baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default))
using (var key = baseKey.OpenSubKey(path))
{
if (key == null) return defaultValue;
var val = key.GetValue(name);
return val is T t ? t : defaultValue;
}
}
public static void SetValue(RegistryHive hive, string path, string name, object value, RegistryValueKind kind = RegistryValueKind.String)
{
using (var baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default))
using (var key = baseKey.CreateSubKey(path))
{
key.SetValue(name, value, kind);
}
}
public static void DeleteKey(RegistryHive hive, string path, bool recursive = false)
{
using (var baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default))
{
if (recursive) baseKey.DeleteSubKeyTree(path, false);
else baseKey.DeleteSubKey(path, false);
}
}
public static string[] GetSubKeyNames(RegistryHive hive, string path)
{
using (var baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default))
using (var key = baseKey.OpenSubKey(path))
return key?.GetSubKeyNames() ?? Array.Empty();
}
public static string[] GetValueNames(RegistryHive hive, string path)
{
using (var baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default))
using (var key = baseKey.OpenSubKey(path))
return key?.GetValueNames() ?? Array.Empty();
}
}
// 使用範例
RegistryHelper.SetValue(RegistryHive.CurrentUser, @"Software\MyApp", "Version", "1.0.0");
string ver = RegistryHelper.GetValue(RegistryHive.CurrentUser, @"Software\MyApp", "Version", "0.0.0");
64 位元系統上,32 位元程式存取 HKLM\Software 會被重導向至 HKLM\Software\WOW6432Node。
// 強制存取 64 位元視圖
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
using (var key = baseKey.OpenSubKey(@"Software\MyApp", true))
{
key.SetValue("Test64", "Value");
}
// 強制存取 32 位元視圖
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
using (var key = baseKey.OpenSubKey(@"Software\MyApp", true))
{
key.SetValue("Test32", "Value");
}
Registry.LocalMachine 寫入需**管理員權限** (UAC 提升)。RegistryKey.OpenSubKey(path, RegistryRights.WriteKey) 精確控制權限。ProtectedData) 或憑證存放區。| 錯誤 | 原因 | 解決 |
|---|---|---|
| SecurityException | 無權限寫入 HKLM | 啟動器加入 requireAdministrator 或改寫 HKCU |
| ArgumentException: 預設值無法刪除 | 呼叫 DeleteValue("") | 預設值只能修改不能刪除 |
| NullReferenceException | OpenSubKey 回傳 null 直接操作 | 檢查 null 或使用 ?. 運算子 |
| 資料型別不符 | GetValue 回傳 object 需轉型 | 使用 as / 模式比對 / 轉換方法 |
掌握 RegistryKey 的 CreateSubKey/OpenSubKey/DeleteSubKeyTree、SetValue/GetValue/DeleteValue、RegistryValueKind 型別、32/64 位元視圖切換、using 釋放資源,即可涵蓋 99% 登錄表操作需求。建議封裝 RegistryHelper 統一錯誤處理與日誌記錄。