用C#实现注册表的读\写是一件很容易的事情,在此不做详细的讲解。
用C#操作注册表主要用到的两个函数为(已经渗透到下面的实例程序中,注:要引入Microsoft.Win32命名空间):
1:读取键值-->Registry.LocalMachine.OpenSubKey(“..Key的路径...”, true),这里的第2个bool类型的参数含义为:标志打开的键值是否可以更改(即:是否可以用SetValue()给键赋值),然后调用GetValue()方法就能把键值读取出来。
微软为了让32位程序不做任何修改就能运行在64的操作系统上,添加了一个十分重要的WOW64子系统来实现这个功能,WOW64是Windows-32-on-Windows-64的简称,从总体上来说,WOW64是一套基于用户模式的动态链接库,它可以把32位应用程序的发出的命令翻译成64位系统可以接受的格式,即:WOW 层处理诸如在 32 位和 64 位模式之间切换处理器以及模拟 32 位系统的事务。
32位与64位特点的两个重要表现方面为:文件系统与注册表。
文件系统:32位进程不能加载64位Dll,64位进程也不可以加载32位Dll。
注册表:为了防止注册表键冲突,64位机器注册表信息分成了两个部分。一部分是专门给64位系统(即:64位程序)访问的,另一部分是专门给32位系统(即:32位程序)访问的,放在Wow6432Node下面。(Wow6432Node这个节 点存在于HKEY_LOCAL_MACHINE和HKEY_CURRENT_USER下面)
既然知道了注册表信息分成了两部分,那么就可以想到:用32位程序和64位程序去操作注册表的时候会操作不同位置的注册表信息。下面例子可以充分证明这种说法。
public class Utility
{
#region 32位程序读写64注册表
static UIntPtr HKEY_CLASSES_ROOT = (UIntPtr)0x80000000;
static UIntPtr HKEY_CURRENT_USER = (UIntPtr)0x80000001;
static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
static UIntPtr HKEY_USERS = (UIntPtr)0x80000003;
static UIntPtr HKEY_CURRENT_CONFIG = (UIntPtr)0x80000005;
// 关闭64位(文件系统)的操作转向
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
// 开启64位(文件系统)的操作转向
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);
// 获取操作Key值句柄
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions,
int samDesired, out IntPtr phkResult);
//关闭注册表转向(禁用特定项的注册表反射)
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern long RegDisableReflectionKey(IntPtr hKey);
//使能注册表转向(开启特定项的注册表反射)
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern long RegEnableReflectionKey(IntPtr hKey);
//获取Key值(即:Key值句柄所标志的Key对象的值)
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, int lpReserved,
out uint lpType, System.Text.StringBuilder lpData,
ref uint lpcbData);
private static UIntPtr TransferKeyName(string keyName)
{
switch (keyName)
{
case "HKEY_CLASSES_ROOT":
return HKEY_CLASSES_ROOT;
case "HKEY_CURRENT_USER":
return HKEY_CURRENT_USER;
case "HKEY_LOCAL_MACHINE":
return HKEY_LOCAL_MACHINE;
case "HKEY_USERS":
return HKEY_USERS;
case "HKEY_CURRENT_CONFIG":
return HKEY_CURRENT_CONFIG;
}
return HKEY_CLASSES_ROOT;
}
public static string Get64BitRegistryKey(string parentKeyName, string subKeyName, string keyName)
{
int KEY_QUERY_VALUE = (0x0001);
int KEY_WOW64_64KEY = (0x0100);
int KEY_ALL_WOW64 = (KEY_QUERY_VALUE | KEY_WOW64_64KEY);
try
{
//将Windows注册表主键名转化成为不带正负号的整形句柄(与平台是32或者64位有关)
UIntPtr hKey = TransferKeyName(parentKeyName);
//声明将要获取Key值的句柄
IntPtr pHKey = IntPtr.Zero;
//记录读取到的Key值
StringBuilder result = new StringBuilder("".PadLeft(1024));
uint resultSize = 1024;
uint lpType = 0;
//关闭文件系统转向
IntPtr oldWOW64State = new IntPtr();
if (Wow64DisableWow64FsRedirection(ref oldWOW64State))
{
//获得操作Key值的句柄
RegOpenKeyEx(hKey, subKeyName, 0, KEY_ALL_WOW64, out pHKey);
//关闭注册表转向(禁止特定项的注册表反射)
RegDisableReflectionKey(pHKey);
//获取访问的Key值
RegQueryValueEx(pHKey, keyName, 0, out lpType, result, ref resultSize);
//打开注册表转向(开启特定项的注册表反射)
RegEnableReflectionKey(pHKey);
}
//打开文件系统转向
Wow64RevertWow64FsRedirection(oldWOW64State);
//返回Key值
return result.ToString().Trim();
}
catch (Exception ex)
{
return null;
}
}
#endregion
}
那么如何调用呢?
private void button2_Click(object sender, EventArgs e)
{
string myParentKeyName = "HKEY_LOCAL_MACHINE";
string mySubKeyName = @"SOFTWARE\Microsoft\Internet Explorer";
string myKeyName = "Version";
string value = string.Empty;
value = Utility.Get64BitRegistryKey(myParentKeyName, mySubKeyName, myKeyName);
MessageBox.Show(value);
}
Get64BitRegistryKey函数的三个参数分别代表:主键名(如:HKEY_LOCAL_MACHINE等),子键名,Key名,返回的是Key的Value(64位系统注册表的键值),通过上面的方法就完全可以实现用32程序访问64位系统注册表(即:64位程序所访问的注册表位置)。