最近晚上业余时间在写一个操作注册表的软件,使用Microsoft.Win32.RegistryKey多了,发现RegistryKey提供的功能还是有待于加强。
从Windows Xp开始比较常用的键值类型为五类,regedit.exe直接支持这些类型数据的编辑。
REG_BINARY |
未处理的二进制数据。多数硬件组件信息都以二进制数据存储,而以十六进制格式显示在注册表编辑器中。 |
REG_DWORD |
数据由 4 个字节长的数表示。许多设备驱动程序和服务的参数是这种类型并在注册表编辑器中以二进制、十六进制或十进制的格式显示。 |
REG_EXPAND_SZ |
长度可变的数据串。该数据类型包含在程序或服务使用该数据时确定的变量。 |
REG_MULTI_SZ |
多重字符串。包含了用户可读取格式的列表或多值的值通常为该类型。项用空格、逗号或其他标记分开。 |
REG_SZ |
固定长度的文本串。 |
通过RegistryKey.GetValue及其重载方法得到的值类型对应为
REG_BINARY |
byte [ ] |
REG_DWORD |
Int32 |
REG_EXPAND_SZ |
String |
REG_MULTI_SZ |
String [] |
REG_SZ |
String |
从上表看出有两个String类型,查看msdn文档并没有提供区分REG_SZ和REG_EXPAND_SZ的方法。
在使用RegistryKey.SetValue方法更新数据时如果类型为REG_MULTI_SZ会自动被转换为REG_SZ类型。
对于REG_DWORD类型这里为Int32类型,Int32.MaxValue字段的值为 2,147,483,647;即十六进制的 0x7FFFFFFF。通过注册表编辑可以设置最大到0xFFFFFFFF,也就是说使用Int64类型才可以满足需要。通过RegistryKey.GetValue获取的值大于Int32.MaxValue就会溢出成为负数。
下面是笔者得到的测试数据:
实际数据 得到的数据 备注
============================
4294967000 -296
4294967295 -1
2147483647 2147483647 0x7FFFFFFF (最大整数)
2147483648 -2147483648
通过上面的一组数据可以找到下面规律,
Dwrod值最大为0xFFFFFFFF ,即十进制的 4294967295。
在得到负数的情况下,通过以下方式得到修正后的值,
修正后值 = 4294967295 + 得到的数据(负数) + 1
如果得到十六进制的字符串如下,
十六进制字符串= (得到的数据 ).ToString("x8");
也可以使用Convert类来操作。
而通过RegistryKey.SetValue方法更新一个大于Int32.MaxValue的数值也就是Int64类型数据,就会把实际注册表中的Dword类型变为String 类型。
比如:
registrykey.SetValue(“valueName”,4294967000);
那valueName类型有原来的REG_DWORD 转变为REG_SZ。
解决办法就是对大于Int32. MaxValue的数据进行获取时的反向计算。
实际更新值 = 数值(大于Int32. MaxValue) - 4294967295 – 1
对上面的值进行计算后更新,
-296 = 4294967000 – 4294967295 – 1
registrykey.SetValue(“valueName”, -296 );
上面提到的REG_EXPAND_SZ类型的获取和数据更新笔者通过C#包装Reg.exe命令行程序来间接调用实现。Reg.exe程序只能在Windows XP 和 Windows 2003下使用。包装Reg.exe的类这里就不讲了,实现比较容易。Reg.exe的使用帮助可以查看Windows系统的帮助和支持。
补充:
在.net framewrok 2.0版中,这部分的功能得到了增强,提供了RegistryValueKind和RegistryValueOptions枚举类型,通过RegistryKey类可以处理各种类型的数据,并增加了对项节点权限的访问。