原文:[C#]注册表操作
概念
在介绍注册表操作前,有必要了解注册表的一些基本常识。
在此简要介绍一下。
注册表
注册表(Registry,繁体中文版Windows称之为登录档)是Microsoft Windows中的一个重要的数据库,用于存储系统和应用程序的设置信息。注册表组织层次结构的格式,基于存储在它的元素的逻辑顺序。 当将信息存储在注册表中,选择要存储的信息类型所基于的适当位置。
在Windows 3.x操作系统中,注册表是一个极小文件,其文件名为Reg.dat,里面只存放了某些文件类型的应用程序关联,大部分的设置放在Win.ini、System.ini等多个初始化INI文件中。由于这些初始化文件不便于管理和维护,时常出现一些因INI文件遭到破坏而导致系统无法启动的问题。为了使系统运行得更为稳定、健壮,Windows 95/98设计师们借用了Windows NT中的注册表的思想,将注册表引入到Windows 95/98操作系统中,而且将INI文件中的大部分设置也移植到注册表中,因此,注册表在Windows 95/98操作系统的启动、运行过程中起着重要的作用。
HKEY(主键)
HEKY:“根键”或“主键”。
windows7中有5个主键:
HKEY_CLASSES_ROOT:保存了所有应用程序运行时必需的信息。
HKEY_CURRENT_USER:保存统当前的用户信息。
HKEY_LOCAL_MACHINE:保存了注册表里的所有与这台计算机有关的配置信息。
HKEY_USERS:保存了缺省用户设置和登录用户的信息。虽然它包含了所有独立用户的设置,但在用户未登录时用户的设置是不可用的。
HKEY_CURRENT_CONFIG:保存了系统中现有的所有配置文件的细节。
key(键)
它包含了附加的文件夹和一个或多个值。
subkey(子键)
在某一个键(父键)下面出现的键(子键)。
打开注册表的方法
点击 开始 -> 运行 -> regedit
注册表操作
RegistryKey 类
表示 Windows 注册表中的项级节点。 此类是注册表封装。
所属命名空间为Microsoft.Win32。
常用方法:
CreateSubKey:创建或打开一个子表项
OpenSubKey:打开一个子表项
SetValue:设置一个变量的值
GetValue:获取一个变量的值
DeleteValue:删除一个变量
MSDN官方例子
using System;
using System.Security.Permissions;
using Microsoft.Win32;
class RegKey
{
static void Main()
{
// Create a subkey named Test9999 under HKEY_CURRENT_USER.
RegistryKey test9999 =
Registry.CurrentUser.CreateSubKey("Test9999");
// Create two subkeys under HKEY_CURRENT_USER\Test9999. The
// keys are disposed when execution exits the using statement.
using(RegistryKey
testName = test9999.CreateSubKey("TestName"),
testSettings = test9999.CreateSubKey("TestSettings"))
{
// Create data for the TestSettings subkey.
testSettings.SetValue("Language", "French");
testSettings.SetValue("Level", "Intermediate");
testSettings.SetValue("ID", 123);
}
// Print the information from the Test9999 subkey.
Console.WriteLine("There are {0} subkeys under {1}.",
test9999.SubKeyCount.ToString(), test9999.Name);
foreach(string subKeyName in test9999.GetSubKeyNames())
{
using(RegistryKey
tempKey = test9999.OpenSubKey(subKeyName))
{
Console.WriteLine("\nThere are {0} values for {1}.",
tempKey.ValueCount.ToString(), tempKey.Name);
foreach(string valueName in tempKey.GetValueNames())
{
Console.WriteLine("{0,-8}: {1}", valueName,
tempKey.GetValue(valueName).ToString());
}
}
}
using(RegistryKey
testSettings = test9999.OpenSubKey("TestSettings", true))
{
// Delete the ID value.
testSettings.DeleteValue("id");
// Verify the deletion.
Console.WriteLine((string)testSettings.GetValue(
"id", "ID not found."));
}
// Delete or close the new subkey.
Console.Write("\nDelete newly created registry key? (Y/N) ");
if(Char.ToUpper(Convert.ToChar(Console.Read())) == 'Y')
{
Registry.CurrentUser.DeleteSubKeyTree("Test9999");
Console.WriteLine("\nRegistry key {0} deleted.",
test9999.Name);
}
else
{
Console.WriteLine("\nRegistry key {0} closed.",
test9999.ToString());
test9999.Close();
}
}
}
应用案例
获取程序的版本号和安装路径
代码:获取OFFICE的版本号和安装路径
using System;
using System.Windows.Forms;
using Microsoft.Win32;
namespace RegistryUtil {
static class Program {
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string version = null;
string path = null;
GetOfficeInfo(out version, out path);
Console.WriteLine(string.Format("OFFICE 版本号:{0}, 安装路径:{1}", version, path));
}
/// <summary>
/// 获取注册表中的OFFICE版本和安装路径信息
/// </summary>
/// <param name="version">出参,版本号</param>
/// <param name="path">出参,安装路径</param>
/// <returns>int错误码</returns>
public static int GetOfficeInfo(out string version, out string path) {
path = string.Empty; // OFFICE安装路径
version = string.Empty; // OFFICE版本
int result = 0;
RegistryKey regKey = null;
try {
regKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Excel.exe"); // Excel程序的注册表路径
string regValue = regKey.GetValue("Path").ToString();
string temp = regValue.Substring(0, regValue.Length - 1);
string versionName = temp.Substring(temp.LastIndexOf("\\") + 1);
switch (versionName) {
case "Office11": //检查本机是否安装Office2003
version = "Office2003";
break;
case "Office12": //检查本机是否安装Office2007
version = "Office2007";
break;
case "Office14": //检查本机是否安装Office2010
version = "Office2010";
break;
case "Office15": //检查本机是否安装Office2013
version = "Office2013";
break;
default:
version = "未知版本!";
break;
}
path = regValue;
} catch (Exception ex) {
result = -1;
Console.WriteLine(ex.Message);
} finally {
if (null != regKey) {
regKey.Close();
regKey = null;
}
}
return result;
}
}
}
如何设置程序开机自启动
如果想要将一个exe程序设置为开机自启动,其实就是在HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run注册表项中添加一个注册表变量,这个变量的值是程序的所在路径。
具体操作步骤是:
1、使用RegistryKey类的CreateSubKey方法打开HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run变量,如果不存在,这个方法会直接创建。
2、如果是添加一个变量的键值可以使用RegistryKey类的SetValue方法;
如果是删除一个变量的键值可以使用RegistryKey类的DeleteValue方法。
代码: 设置程序开机自启动状态
using System;
using System.Windows.Forms;
using Microsoft.Win32;
namespace RegistryUtil {
static class Program {
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SetAutoBootStatu(true);
}
/// <summary>
/// 在注册表中添加、删除开机自启动键值
/// </summary>
public static int SetAutoBootStatu(bool isAutoBoot) {
try {
string execPath = Application.ExecutablePath;
RegistryKey rk = Registry.LocalMachine;
RegistryKey rk2 = rk.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
if (isAutoBoot) {
rk2.SetValue("MyExec", execPath);
Console.WriteLine(string.Format("[注册表操作]添加注册表键值:path = {0}, key = {1}, value = {2} 成功", rk2.Name, "TuniuAutoboot", execPath));
} else {
rk2.DeleteValue("MyExec", false);
Console.WriteLine(string.Format("[注册表操作]删除注册表键值:path = {0}, key = {1} 成功", rk2.Name, "TuniuAutoboot"));
}
rk2.Close();
rk.Close();
return 0;
} catch (Exception ex) {
Console.WriteLine(string.Format("[注册表操作]向注册表写开机启动信息失败, Exception: {0}", ex.Message));
return -1;
}
}
}
}
需要注意的是:
Windows中微软的注册表信息是分32位和64位的:
32位:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft
64位:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft
以下代码
RegistryKey rk = Registry.LocalMachine;
RegistryKey rk2 = rk.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
rk2.SetValue("MyExec", execPath);
在32位机器上执行,那么没有问题,变量会创建在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run下。但是如果在64位机器上执行,会自动创建在
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
如何添加、删除、刷新环境变量
很多时候,我们需要设置系统环境变量(比如:设置Java jdk、tomcat的环境变量),使得计算机可以识别要执行程序的路径,这样就可以直接运行它。我个人理解,环境变量就像是计算机的全局变量,只要设置了,系统就可以任何文件路径识别它。
学计算机的基本都会人工大法:
点击 计算机->属性->高级系统设置->环境变量->系统环境变量
然后在Path中添加你要执行程序的所在路径。So Easy。
如果要在程序中去设置,该如何做呢。
首先,你需要了解的是:
系统环境变量列表实际上和注册表中的HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment项一一对应。
你修改了这个注册表项的键值就是在修改系统环境变量。
无论是添加、删除一个执行路径都需要执行以下步骤:
1、 使用RegistryKey类的OpenSubKey方法打开HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment表项。
2、 使用RegistryKey类的GetValue方法读取表项中的变量。
3、 键值就是一个字符串,修改后,使用RegistryKey类的SetValue方法写入注册表中。
4、 使用windows系统函数SendMessageTimeout刷新环境变量。
需要说明的是:如果不刷新环境变量。计算机并不一定让已修改的变量立即生效。虽然你打开注册表或环境变量时,可以看到值确实已经发生了变化。
此外,还需要注意一点,windows还有一个SendMessage函数。此函数必须得到消息回应才会继续执行,使用此函数发送刷新变量消息,可能会使程序挂住。
代码:将当前执行程序的路径写入系统环境变量Path中
using System;
using System.IO;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Runtime.InteropServices;
namespace RegistryUtil {
static class Program {
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AddValueToSysPathEnv(Environment.CurrentDirectory);
}
/// <summary>
/// 为系统环境变量Path添加一个path路径
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static int AddValueToSysPathEnv(string value) {
int code = 0;
RegistryKey regEnvironment = null;
try {
regEnvironment = Registry.LocalMachine.OpenSubKey("SYSTEM\\ControlSet001\\Control\\Session Manager\\Environment", true);
if (null == regEnvironment) {
return -1;
}
string regValue = (string)regEnvironment.GetValue("Path");
regValue = value + Path.PathSeparator + regValue;
Console.WriteLine("环境变量: " + regValue);
regEnvironment.SetValue("Path", regValue);
// 刷新环境变量,否则不一定即时生效
IntPtr result;
SendMessageTimeout(new IntPtr(HWND_BROADCAST),
WM_SETTINGCHANGE,
IntPtr.Zero,
"Environment",
SendMessageTimeoutFlags.SMTO_ABORTIFHUNG,
200,
out result);
Console.WriteLine("Result: " + result);
regEnvironment.Flush();
} catch (Exception ex) {
Console.WriteLine(ex);
code = -1;
} finally {
if (null != regEnvironment) {
regEnvironment.Close();
regEnvironment = null;
}
}
return code;
}
[Flags]
public enum SendMessageTimeoutFlags : uint {
SMTO_NORMAL = 0x0000,
SMTO_BLOCK = 0x0001,
SMTO_ABORTIFHUNG = 0x0002,
SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
}
const int WM_SETTINGCHANGE = 0x001A;
const int HWND_BROADCAST = 0xffff;
/// <summary>
/// windows发送消息函数
/// </summary>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
uint Msg,
IntPtr wParam,
string lParam,
SendMessageTimeoutFlags fuFlags,
uint uTimeout,
out IntPtr lpdwResult);
}
}
参考资料
RegistryKey 类
https://msdn.microsoft.com/zh-cn/library/microsoft.win32.registrykey.aspx
SendMessageTimeout
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644952(v=vs.85).aspx