环境:
- window 10企业版
- .netcore 3.1
- vs 2019 16.4.5
- 控制台程序以管理员身份运行
参照:
一、window注册表简介
1.1 什么是注册表
注册表是window操作系统存储数据的地方,可以认为是window自身的一个小型数据库。所有window软件都可以在安装或运行的时候向注册表添加或读取数据。同时window操作系统也会读取里面的内容以决定自己的行为。
举个例子:
- 迅雷软件安装后会在注册表中写入
HKEY_CLASSES_ROOT\thunder
,从而指示操作系统:当打开thunder://12345这样的地址的时候启动迅雷程序,如下图所示:
- 你可以修改注册表的值,以达到清除快捷方式箭头的目的
删除HKEY_CLASSES_ROOT\lnkfile
项下面的IsShortcut值,然后重启操作系统或者在任务管理器中重启window 资源管理器你就会发现桌面上的图标箭头消失了,如下:
- 修改注册表项
HKEY_CURRENT_USER\Control Panel\Desktop
下PaintDesktopVersion的值为1,window桌面右下角将会显示window操作系统版本号:
1.2 注册表的数据结构
注册表是一个树状结构,它有五大根节点,这五大根节点有不同的作用。根节点下可以有很多子节点,每个子节点称之为“项”,而每个子节点又可以有自己的数据值,这些数据值按照数据类型划分为“字符串”、“扩展字符串”、“多行字符串”、“32位无符号整数”、“64位无符号整数”和“二进制数据”。
1.2.1 注册表的五大根节点
- HKEY_CLASSES_ROOT:
该根键包括启动应用程序所需的全部信息,包括扩展名,应用程序与文档之间的关系,驱动程序名,DDE和OLE信息,类ID编号和应用程序与文档的图标等。 - HKEY_CURRENT_USER:
该根键包括当前登录用户的配置信息,包括环境变量,个人程序以及桌面设置等 - HKEY_LOCAL_MACHINE:
该根键包括本地计算机的系统信息,包括硬件和操作系统信息,安全数据和计算机专用的各类软件设置信息 - HKEY_USERS:
该根键包括计算机的所有用户使用的配置数据,这些数据只有在用户登录系统时才能访问。这些信息告诉系统当前用户使用的图标,激活的程序组,开始菜单的内容以及颜色,字体。 - HKEY_CURRENT_CONFIG:
该根键包括当前硬件的配置信息,其中的信息是从KEY_LOCAL_MACHINE中映射出来的。
1.2.2 数据值的数据类型
- 字符串
简单字符串:REG_SZ
多行字符串:REG_MULTI_SZ,获取的是字符串数组,不能解析%windir%等变量
扩展字符串:REG_EXPAND_SZ,简单字符串上增加解析%windir%等变量的功能 - 数字(正整数)
int32:REG_DWORD,双子节 0 - 4294967295(2^32-1)
int64:REG_QWORD,四个字节 0 - (Math.Pow(2,64)-1) - 字节数组
byte[]:REG_BINARY
1.2.3 注册表项的默认值
每个项都允许有一个默认值,它的以空字符串("")作为关键字的简单字符串(注意,不是扩展字符串),如果你设置了它就存在(可以遍历所有的数据,会发现""),没设置值的话它就不存在(遍历数据的时候不会看到"")
二、c#读写注册表
基于上面对注册表的分析,我们需要对注册表进行读写操作,主要应用RegistryKey
对象,下面是我封装的注册表操作的帮助类,200多行,包含的判断、读取、写入等操作:
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
/* 注册表知识点:
* 1. 注册表有5大根节点,所有的配置都在这5个下面,所以我们读写的path里都以5大根节点字符串开头(HKEY_LOCAL_MACHINE\\SOFTWARE\\FileZilla 3)
* 2. 注册表中有项和值,项就像是文件夹、而值就像是一个Dictinary<string,byte[]/int32/int64/string/string[]>
* 3. 注册表中值的类型
* 字符串
* 简单字符串:REG_SZ
* 多行字符串:REG_MULTI_SZ,获取的是字符串数组,不能解析%windir%等变量
* 扩展字符串:REG_EXPAND_SZ,简单字符串上增加解析%windir%等变量的功能
* 数字(正整数)
* int32:REG_DWORD,双子节 0 - 4294967295(2^32-1)
* int64:REG_QWORD,四个字节 0 - (Math.Pow(2,64)-1)
* 字节数组
* byte[]:REG_BINARY
* 4. 注册表项的默认值
* 每个项都允许有一个默认值,它的以空字符串("")作为关键字的简单字符串(注意,不是扩展字符串),如果你设置了它就存在(可以遍历所有的数据,会发现""),没设置值的话它就不存在(遍历数据的时候不会看到"")
*
*/
namespace ConsoleApp24
{
public class RegistryUtil
{
#region 内部使用
private static Dictionary<string, RegistryHive> roots = new Dictionary<string, RegistryHive>()
{
{"HKEY_CLASSES_ROOT",RegistryHive.ClassesRoot},
{"HKEY_CURRENT_USER",RegistryHive.CurrentUser},
{"HKEY_LOCAL_MACHINE",RegistryHive.LocalMachine},
{"HKEY_USERS",RegistryHive.Users},
{"HKEY_CURRENT_CONFIG",RegistryHive.CurrentConfig}
};
private RegistryKey GetRoot(string path)
{
if (string.IsNullOrWhiteSpace(path)) return null;
path = path.Trim('\\', '/');
foreach (var i in roots)
{
if (path.StartsWith(i.Key))
{
return RegistryKey.OpenBaseKey(i.Value,
Environment.Is64BitOperatingSystem
? RegistryView.Registry64
: RegistryView.Registry32);
}
}
return null;
}
private static ValueTuple<string, RegistryKey> PrunePath(string path)
{
path = path.Trim('\\', '/').Replace('/', '\\');
RegistryKey baseKey = null;
foreach (var i in roots)
{
if (path.StartsWith(i.Key))
{
baseKey = RegistryKey.OpenBaseKey(i.Value,
Environment.Is64BitOperatingSystem
? RegistryView.Registry64
: RegistryView.Registry32);
path = path.Substring(i.Key.Length).Trim('\\');
break;
}
}
if (baseKey == null)
{
baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
Environment.Is64BitOperatingSystem
? RegistryView.Registry64
: RegistryView.Registry32);
}
return new ValueTuple<string, RegistryKey>(path, baseKey);
}
#endregion
#region 判断、列出数据值的关键字、删除项或数据值
/// <summary>
/// 判断注册表项或值是否存在
/// </summary>
/// <param name="path">项路径</param>
/// <param name="keyname">值的名称</param>
/// <returns></returns>
public static bool Exists(string path, string keyname = null)
{
var res = PrunePath(path);
var root = res.Item2;
path = res.Item1;
RegistryKey key = root.OpenSubKey(path);
if (key == null) return false;
if (keyname == null) return true;
return key.GetValueNames().ToList().Contains(keyname);
}
/// <summary>
/// 返回注册项下的所有数据值名称,如果不存在这个项就返回null
/// </summary>
/// <param name="path">注册项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <returns></returns>
public static List<string> ListDataKeys(string path)
{
var res = PrunePath(path);
var root = res.Item2;
path = res.Item1;
RegistryKey key = root.OpenSubKey(path);
if (key == null) return null;
return key.GetValueNames().ToList();
}
/// <summary>
/// 删除指定的项(包括子项和数据值)
/// </summary>
/// <param name="path">注册项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
public static void DeletePath(string path)
{
if (Exists(path))
{
ValueTuple<string, RegistryKey> res = PrunePath(path);
path = res.Item1;
RegistryKey root = res.Item2;
root.DeleteSubKeyTree(path);
}
}
/// <summary>
/// 删除指定项下的指定数据值
/// </summary>
/// <param name="path">注册项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param keyname="keyname">注册项下的数据值关键字,如:teststring</param>
public static void DeleteValue(string path, string keyname)
{
if (Exists(path, keyname))
{
ValueTuple<string, RegistryKey> res = PrunePath(path);
path = res.Item1;
RegistryKey root = res.Item2;
RegistryKey key = root.OpenSubKey(path, true);
key.DeleteValue(keyname);
}
}
#endregion
#region 读取注册表的值
private static object GetValue(string path, string keyname = "")
{
var res = PrunePath(path);
var root = res.Item2;
path = res.Item1;
RegistryKey key = root.OpenSubKey(path);
if (key == null) return null;
var obj = key.GetValue(keyname);
return obj;
}
/// <summary>
/// 读取注册项下的字符串数据(REG_SZ和REG_EXPAND_SZ),如果keyname为空就是读取默认值
/// </summary>
/// <param name="path">项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据值名称,如:string_a</param>
/// <returns></returns>
public static string GetString(string path, string keyname = "")
{
var obj = GetValue(path, keyname);
if (obj == null) return null;
return obj as string;
}
/// <summary>
/// 读取注册项下的字节数据(REG_BINARY)
/// </summary>
/// <param name="path">项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据值名称,如:binary_123456789</param>
/// <returns></returns>
public static byte[] GetByteArray(string path, string keyname)
{
var obj = GetValue(path, keyname);
if (obj == null) return null;
return obj as byte[];
}
/// <summary>
/// 读取注册项下的字节数据(REG_DWORD)
/// </summary>
/// <param name="path">项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据值名称,如:dword</param>
/// <returns></returns>
public static Int32? GetInt32(string path, string keyname)
{
var obj = GetValue(path, keyname);
if (obj == null) return null;
return (Int32)obj;
}
/// <summary>
/// 读取注册项下的字节数据(REG_QWORD)
/// </summary>
/// <param name="path">项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据值名称,如:qword</param>
/// <returns></returns>
public static Int64? GetInt64(string path, string keyname)
{
var obj = GetValue(path, keyname);
if (obj == null) return null;
return (Int64)obj;
}
/// <summary>
/// 综合GetInt32和GetInt64方法,可以取出REG_DWORD和REG_QWORD类型的数据
/// </summary>
/// <param name="path">项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据值名称,如:testint</param>
/// <returns></returns>
public static int? GetInt(string path, string keyname)
{
var obj = GetValue(path, keyname);
if (obj == null) return null;
if (obj is Int32) return (int)obj;
if (obj is Int64) return (int)(long)obj;
return null;
}
/// <summary>
/// 读取注册项下的字节数据(REG_MULTI_SZ)
/// </summary>
/// <param name="path">项路径,如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据值名称,如:string_multi</param>
/// <returns></returns>
public static string[] GetStringArray(string path, string keyname)
{
var obj = GetValue(path, keyname);
if (obj == null) return null;
return obj as string[];
}
#endregion
#region 设置注册项的数据值
private static void SetValue(string path, string keyname, object value, RegistryValueKind dataKind)
{
var res = PrunePath(path);
var root = res.Item2;
path = res.Item1;
RegistryKey key = root.CreateSubKey(path, true);
key.SetValue(keyname, value, dataKind);
}
/// <summary>
/// 设置注册项的默认值,注意:如果指定的path不存在则会新建
/// </summary>
/// <param name="path">注册项路径,比如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="value">字符串,类型为REG_SZ</param>
public static void SetDefault(string path, string value)
{
SetValue(path, "", value, RegistryValueKind.String);
}
/// <summary>
/// 给指定注册项设置键值对(REG_SZ),注意:如果指定的path不存在则会新建
/// </summary>
/// <param name="path">注册项路径,比如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据的名称</param>
/// <param name="value">数据值</param>
public static void SetString(string path, string keyname, string value = "")
{
if (string.IsNullOrWhiteSpace(keyname)) throw new Exception("必须指定数据值的关键字,如果想设置【(默认)】,那么调用SetDefault(string path,string value)方法");
SetValue(path, keyname, value, RegistryValueKind.String);
}
/// <summary>
/// 给指定注册项设置键值对(REG_EXPAND_SZ),注意:如果指定的path不存在则会新建
/// </summary>
/// <param name="path">注册项路径,比如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据的名称</param>
/// <param name="value">数据值,如:xiao%windir%ming</param>
public static void SetStringExpand(string path, string keyname, string value = "")
{
if (string.IsNullOrWhiteSpace(keyname)) throw new Exception("必须指定数据值的关键字,如果想设置【(默认)】,那么调用SetDefault(string path,string value)方法");
SetValue(path, keyname, value, RegistryValueKind.ExpandString);
}
/// <summary>
/// 给指定注册项设置键值对(REG_MULTI_SZ),注意:如果指定的path不存在则会新建
/// </summary>
/// <param name="path">注册项路径,比如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据的名称</param>
/// <param name="value">数据值,如:new string[2] { "xiaoming", "xi" }</param>
public static void SetStringArray(string path, string keyname, string[] value)
{
if (string.IsNullOrWhiteSpace(keyname)) throw new Exception("必须指定数据值的关键字,如果想设置【(默认)】,那么调用SetDefault(string path,string value)方法");
if (value == null) throw new Exception("必须指定一个数组!");
SetValue(path, keyname, value, RegistryValueKind.MultiString);
}
/// <summary>
/// 给指定注册项设置键值对(REG_DWORD),注意:如果指定的path不存在则会新建
/// </summary>
/// <param name="path">注册项路径,比如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据的名称</param>
/// <param name="value">数据值,如:456</param>
public static void SetInt32(string path, string keyname, Int32 value)
{
if (string.IsNullOrWhiteSpace(keyname)) throw new Exception("必须指定数据值的关键字,如果想设置【(默认)】,那么调用SetDefault(string path,string value)方法");
SetValue(path, keyname, value, RegistryValueKind.DWord);
}
/// <summary>
/// 给指定注册项设置键值对(REG_QWORD),注意:如果指定的path不存在则会新建
/// </summary>
/// <param name="path">注册项路径,比如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据的名称</param>
/// <param name="value">数据值,如:789</param>
public static void SetInt64(string path, string keyname, Int64 value)
{
if (string.IsNullOrWhiteSpace(keyname)) throw new Exception("必须指定数据值的关键字,如果想设置【(默认)】,那么调用SetDefault(string path,string value)方法");
SetValue(path, keyname, value, RegistryValueKind.QWord);
}
/// <summary>
/// 综合SetInt32和SetInt64,存储的是RED_DWORD类型,注意:如果指定的path不存在则会新建
/// </summary>
/// <param name="path">注册项路径,比如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据的名称</param>
/// <param name="value">数据值,如:789</param>
public static void SetInt(string path, string keyname, int value)
{
if (string.IsNullOrWhiteSpace(keyname)) throw new Exception("必须指定数据值的关键字,如果想设置【(默认)】,那么调用SetDefault(string path,string value)方法");
SetValue(path, keyname, value, RegistryValueKind.DWord);
}
/// <summary>
/// 给指定注册项设置键值对(REG_BINARY),注意:如果指定的path不存在则会新建
/// </summary>
/// <param name="path">注册项路径,比如:HKEY_CURRENT_CONFIG\test\test1</param>
/// <param name="keyname">数据的名称</param>
/// <param name="value">数据值,如:new byte[2] { 0x20, 0x45 }</param>
public static void SetByteArray(string path, string keyname, byte[] value)
{
if (string.IsNullOrWhiteSpace(keyname)) throw new Exception("必须指定数据值的关键字,如果想设置【(默认)】,那么调用SetDefault(string path,string value)方法");
SetValue(path, keyname, value, RegistryValueKind.Binary);
}
#endregion
}
}