C# 注册表操作 概述
注册表概述
首先介绍下Windows操作系统中的注册表是什么?有什么作用?。
很早以前的注册表咱就不管了,只说说目前主流的几个Windows操作系统中的注册表。按照我个人的理解,注册表在操作系统中的角色是一个巨大的配置文件数据库。这个特殊的“数据库”里面储存着大量的操作系统配置信息。
比如是否使用屏保、使用的屏保文件的路径、是否开启来宾用户、两次鼠标点击间隔在多少毫秒内才算双击、是否自动排列图标、按照什么顺序排列图标、鼠标的指针移动速速、使用什么连接连接到网络、是否开启系统防火墙、是否开启自动更新、“我的文档”的路径、“我的电脑”的图标路径、腾讯QQ可执行文件路径等等等等……
为什么可以把原本在C盘的“我的文档”移动到D盘,就是因为修改了注册表里标示“我的文档”的路径的键的值。
为什么有时在网页上点击类似于“QQ会话”图片的图片可以启动QQ聊天软件?网页怎么知道我的QQ安装在何处?因为每次安装QQ的时候QQ安装程序都会在注册表中添加一条记录,这个记录便是QQ的安装路径,在网页上点击图片后被执行的程序只要读取这个位置的路径便可以知道“QQ.exe”在哪,然后启动它。
这就是注册表的作用——它是操作系统中的配置信息数据库(个人通俗描述)。
所以,我们可以用这个“数据库”来储存我们锁屏工具的密码,虽然注册表所有人都可以打开看,但是估计一般人看到注册表里面的数据都会晕的,更不会去找你的密码放在哪了,更何况就算找到了它也是经过加密的。安全性方面我觉得这样已经比较可靠了,我知道世上什么高手都有,但是我觉得没有几个人会有兴趣来研究我的锁屏工具的密码的。
在命令行输入命令“regedit”打开注册表编辑器,如图:
根据这后两张图我们可以看到注册表是以树形结构来存储数据的,这个树的根节点叫做“我的电脑”,然后下面有5个主节点。这5个主节点下分别对应储存这些配置信息(个人描述不专业,下列介绍来自百度百科):
在注册表中HKEY_CLASSES_ROOT是系统中控制所有数据文件的项。这个在Win95和Winnt中是相通的。HKEY_CLASSES_ROOT控制键包括了所有文件扩展和所有和执行文件相关的文件。它同样也决定了当一个文件被双击时起反应的相关应用程序。
HKEY_CURRENT_USER包含着在HKEY_USERS安全辨别里列出的同样信息。任何在HKEY_CURRENT_USER里的改动也都会立即HKEY_USERS改动。相反也是这样。
HKEY_CURRENT_USER允许程序员和开发者易于存取目前登陆用户的设置。通过建立这个键,微软很容易在不涉及到用户的SID下改变,添加和设置。
也就是说,所有当前的操作改变只是针对当前用户而改变,并不影响其他用户。
win95一般只使用一个硬件配置文件。如果有多个硬件配置文件。HKEY_LOCAL_MACHINE/Config中就会添加一个键。HKEY_LOCAL_MACHINE/Config包含了HKEY_LOCAL_MACHINE中相同的数据
在启动时,你可以选择你愿意使用的配置文件。如果有多个安装,每次系统重新启动时,你就必须选择.HKEY_CURRENT_CONFIG是在启动时控制目前硬件配置的键
在系统启动以后,任何地方的变化都会自动影响到它。程序员经常使用HKEY_CURRENT_CONFIG方便的来存取配置信息。
HKEY_CURRENT_CONFIG包括了系统中现有的所有配置文件的细节。你的选择影响了哪一个硬件配置文件成为现在的。举例来说,如果配置0002被选择了,所有0002的配置信息会被映射到这些键上
HKEY_CURRENT_CONFIG允许软件和设备驱动程序员很方便的更新注册表,而不涉及到多个配置文件信息。 HKEY_LOCAL_MACHINE中同样的数据和任何注册表的变化都会同时的变化。
HKEY_USERS将缺省用户和目前登陆用户的信息输入到注册表编辑器,在win95中,它仅被那些配置文件激活的登陆用户使用,同样在nt下,它也是这样。
win95从user.dat中取得他们的信息,winnt从ntuser.dat中取得信息。.dat文件包含了所有基于用户的注册表设置并且允许你取配置这些用户的环境。如果你改变了缺省用户的设置,所有新用户会继承同样的设置。而且,那些已经被建立的用户变的失效。
HKEY_LOCAL_MACHINE
HKEY_LOCAL_MACHINE是一个显示控制系统和软件的处理键。HKLM键保存着计算机的系统信息。它包括网络和硬件上所有的软件设置。(比如文件的位置,注册和未注册的状态,版本号等等)这些设置和用户无关,因为这些设置是针对使用这个系统的所有用户的。
HKEY_LOCAL_MACHINE节点是我们今天的重点,软件设置信息一般都存放在这里,为什么存放在这个节点下而不存放在其它地方呢?我们把信息藏在一个很少有人知道的地方岂不更加安全么?这是因为,注册表中的每个节点都有权限分配,当然,我们以Administrators的身份进入系统那绝对是哪都能操作的,但是,并不是所有的人都是以管理员的身份进入的系统,所以并不是所有的当前用户都对注册表的所有节点有操作权限。
所以,微软当初在做这个操作系统的时候就安排好了,HKEY_LOCAL_MACHINE节点下的SOFTWARE节点用于各种软件存储信息。
如何称呼注册表中的各“部件”:
项:左半边带有文件夹图标的节点全部都称为项。
键:右半边里面的一行数据就是一个键。
键的名称:如图。
键的类型:最前面说道,注册表是一个“配置信息数据库”,既然是“数据库”,那么,很显然“数据库”是不光能够存储字符串类型数据的。能储存什么数据看图:
我们今天的需求只需要存储字符串类型的数据,所以其它的就不管了。
键的数据:如图。
分析需求并编程实现
说到底,今天我们的需求就是要在注册表中储存锁屏工具的密码,然后实现登陆验证和修改密码的功能。
经过前面对注册表的分析,我们需要在HKEY_LOCAL_MACHINE/SOFTWARE下建立一个自定义项,然后在我们建立的项中插入一个字符串类型的键,并在建中储存我们的密码。
操作注册表引用命名空间:using Microsoft.Win32;
编程思路及代码
· 增
由于注册表中没有专门给锁屏工具存东西的地方,所以,我们每次打开锁屏工具的时候就要看看注册表中的HKEY_LOCAL_MACHINE/SOFTWARE下建立了锁屏工具的数据项和键没有,如果已经建立了,不管。如果没有建立,说明这是第一次运行锁屏工具,在HKEY_LOCAL_MACHINE/SOFTWARE下建立一个名为“Zane”(这是我自己随便起的名字)的项,然后在这个项下面建个字符串类型名为“zane”,值为DESEncrypt.Encrypt("")的键(DESEncrypt类中的Encrypt方法为加密方法,将空字符串加密后再放在注册表安全性更高),这个键的值就是我们第一次使用锁屏工具的默认密码。
关键代码,在Load时调用RegedieValidate()即可(注册表中的路径不分大小写):
/// <summary> /// 检查注册表中是否已经存在Zane项和zane键,如果没有,创建 /// </summary> private void RegedieValidate() { if (!IsRegeditItemExist())//首先判断是否存在Zane项,没有就建立 { RegistryKey key = Registry.LocalMachine;//获取HKEY_LOCAL_MACHINE节点 key.CreateSubKey("software//Zane");//建立该节点,如果该节点已经存在,则不影响 } if (!IsRegeditKeyExit())//然后判断Zane项中是否有zane键,没有就添加默认密码记录 { RegistryKey key = Registry.LocalMachine; RegistryKey software = key.OpenSubKey("software//Zane", true); //该项必须已存在 software.SetValue("zane", DESEncrypt.Encrypt(" ")); } } /// <summary> /// 判断是否存在Zane节点 /// </summary> /// <returns></returns> private bool IsRegeditItemExist() { string[] subkeyNames; RegistryKey hkml = Registry.LocalMachine; RegistryKey software = hkml.OpenSubKey("SOFTWARE"); //RegistryKey software = hkml.OpenSubKey("SOFTWARE", true); subkeyNames = software.GetSubKeyNames(); //取得该项下所有子项的名称的序列,并传递给预定的数组中 foreach (string keyName in subkeyNames) //遍历整个数组 { if (keyName == "Zane") //判断子项的名称 { hkml.Close(); return true; } } hkml.Close(); return false; } /// <summary> /// 判断密码是否存在(判断是否存在zane键) /// </summary> /// <returns></returns> private bool IsRegeditKeyExit() { string[] subkeyNames; RegistryKey hkml = Registry.LocalMachine; RegistryKey software = hkml.OpenSubKey("SOFTWARE//Zane"); subkeyNames = software.GetValueNames(); //取得该项下所有键值的名称的序列,并传递给预定的数组中 foreach (string keyName in subkeyNames) { if (keyName == "zane") //判断键值的名称 { hkml.Close(); return true; } } hkml.Close(); return false; }
· 查
这样一来,HKEY_LOCAL_MACHINE/SOFTWARE/Zane下的zane键就是我们储存密码的地方了。
密码储存在这里之后每次解锁就在这里取得密码,然后进行登录验证。
取得HKEY_LOCAL_MACHINE/SOFTWARE/Zane下的zane键的值,并进行登录验证的代码如下:
/// <summary> /// 密码验证 /// </summary> /// <returns></returns> private bool PwdValidate() { RegistryKey Key = Registry.LocalMachine; RegistryKey Zane = Key.OpenSubKey("software//Zane", true); string pwd = Zane.GetValue("zane").ToString(); Zane.Close(); if (DESEncrypt.Encrypt(txtPassword.Text) != pwd) { count++; lblMsg.Text = "密码错误"; if (count >= 4) { lblMsg.Text = "警告:/r/n你猥琐的面孔已被摄像头捕获/r/n并发送到主人邮箱中"; } lblMsg.Visible = true; txtPassword.SelectAll(); return false; } count = 0; txtPassword.Text = ""; return true; }
上面的代码里面包含一些用于提示信息的label的控制,至于用摄像头捕捉猥琐人物的照片,并将照片发送到指定邮箱的功能在后续章节中添加。
· 改
有密码的地方就会有登录验证和修改密码。
private void btnOK_Click(object sender, EventArgs e) { if (txtNew.Text.Trim() == "") { MessageBox.Show("新密码不能为空!"); return; } if (txtNew.Text != txtReset.Text) { MessageBox.Show("两次输入的密码不一致!"); return; } RegistryKey Key = Registry.LocalMachine; RegistryKey Zane = Key.OpenSubKey("software//Zane",true); string pwd = Zane.GetValue("zane").ToString(); if (DESEncrypt.Encrypt(txtOld.Text) != pwd) { MessageBox.Show("密码错误!"); return; } Zane.SetValue("zane", DESEncrypt.Encrypt(txtNew.Text)); Zane.Close(); this.Close();//修改成功后关闭本Form }
· 删
虽然锁屏工具不需要删除注册表中的记录,但是我还是一并把删除注册表中的记录的代码贴出来,这是遍历清空某项的键的代码:
直接删除某项的代码就不贴了,只需要调用父节点的DeleteSubKey("子项的name");就可以删除叫name的子项了,当然,也包括子项中所有的键。private void DeleteRegist(string name) { string[] keys; RegistryKey hkml = Registry.LocalMachine; RegistryKey software = hkml.OpenSubKey("SOFTWARE",true); RegistryKey Zane = software.OpenSubKey("Zane",true); keys = Zane.GetSubKeyNames(); foreach(string key in keys) { if(key == name) Zane.DeleteSubKeyTree(name); } }