.NET 3.5中的RegistryKey.OpenBaseKey有哪些替代方案
本文关键字:方案 OpenBaseKey 中的 RegistryKey NET | 更新日期: 2023-09-27 18:25:38
我一直在处理一个安装程序包,并使用RegistryKey.OpenBaseKey处理自定义操作,这些操作可以打开64位注册表或MSI包中的32位注册表中的键,也可以从中添加/删除键,但这要求我在运行安装程序之前,使用引导程序或其他方法在目标计算机上安装.NET Framework 4,因为OpenBaseKey仅在.NET Framework 4中引入。理想情况下,我只想以.NET Framework 3.5为目标,并且仍然能够像OpenBaseKey中那样修改64位或32位注册表配置单元;那么我就不需要.NET 4和安装它的开销了。
对于那些不想将.NET 4作为先决条件的人来说,是否有OpenBaseKey的替代方案?比如P/调用某个WinAPI方法来启动它,也许吧?我不确定需要什么。
对于那些对.NET早期版本的C#解决方案感兴趣的人来说,为了不必重构太多代码,它并不漂亮,但在这里,使用反射是完全可行的。我在XSharper源代码中发现了这个技巧。
public static class RegistryExtensions
{
public enum RegistryHiveType
{
X86,
X64
}
static Dictionary<RegistryHive, UIntPtr> _hiveKeys = new Dictionary<RegistryHive, UIntPtr> {
{ RegistryHive.ClassesRoot, new UIntPtr(0x80000000u) },
{ RegistryHive.CurrentConfig, new UIntPtr(0x80000005u) },
{ RegistryHive.CurrentUser, new UIntPtr(0x80000001u) },
{ RegistryHive.DynData, new UIntPtr(0x80000006u) },
{ RegistryHive.LocalMachine, new UIntPtr(0x80000002u) },
{ RegistryHive.PerformanceData, new UIntPtr(0x80000004u) },
{ RegistryHive.Users, new UIntPtr(0x80000003u) }
};
static Dictionary<RegistryHiveType, RegistryAccessMask> _accessMasks = new Dictionary<RegistryHiveType, RegistryAccessMask> {
{ RegistryHiveType.X64, RegistryAccessMask.Wow6464 },
{ RegistryHiveType.X86, RegistryAccessMask.WoW6432 }
};
[Flags]
public enum RegistryAccessMask
{
QueryValue = 0x0001,
SetValue = 0x0002,
CreateSubKey = 0x0004,
EnumerateSubKeys = 0x0008,
Notify = 0x0010,
CreateLink = 0x0020,
WoW6432 = 0x0200,
Wow6464 = 0x0100,
Write = 0x20006,
Read = 0x20019,
Execute = 0x20019,
AllAccess = 0xF003F
}
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(
UIntPtr hKey,
string subKey,
uint ulOptions,
uint samDesired,
out IntPtr hkResult);
public static RegistryKey OpenBaseKey(RegistryHive registryHive, RegistryHiveType registryType)
{
UIntPtr hiveKey = _hiveKeys[registryHive];
if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major > 5)
{
RegistryAccessMask flags = RegistryAccessMask.QueryValue | RegistryAccessMask.EnumerateSubKeys | RegistryAccessMask.SetValue | RegistryAccessMask.CreateSubKey | _accessMasks[registryType];
IntPtr keyHandlePointer = IntPtr.Zero;
int result = RegOpenKeyEx(hiveKey, String.Empty, 0, (uint)flags, out keyHandlePointer);
if (result == 0)
{
var safeRegistryHandleType = typeof(SafeHandleZeroOrMinusOneIsInvalid).Assembly.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle");
var safeRegistryHandleConstructor = safeRegistryHandleType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(IntPtr), typeof(bool) }, null); // .NET < 4
if (safeRegistryHandleConstructor == null)
safeRegistryHandleConstructor = safeRegistryHandleType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(IntPtr), typeof(bool) }, null); // .NET >= 4
var keyHandle = safeRegistryHandleConstructor.Invoke(new object[] { keyHandlePointer, true });
var net3Constructor = typeof(RegistryKey).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { safeRegistryHandleType, typeof(bool) }, null);
var net4Constructor = typeof(RegistryKey).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(IntPtr), typeof(bool), typeof(bool), typeof(bool), typeof(bool) }, null);
object key;
if (net4Constructor != null)
key = net4Constructor.Invoke(new object[] { keyHandlePointer, true, false, false, hiveKey == _hiveKeys[RegistryHive.PerformanceData] });
else if (net3Constructor != null)
key = net3Constructor.Invoke(new object[] { keyHandle, true });
else
{
var keyFromHandleMethod = typeof(RegistryKey).GetMethod("FromHandle", BindingFlags.Static | BindingFlags.Public, null, new[] { safeRegistryHandleType }, null);
key = keyFromHandleMethod.Invoke(null, new object[] { keyHandle });
}
var field = typeof(RegistryKey).GetField("keyName", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null)
field.SetValue(key, String.Empty);
return (RegistryKey)key;
}
else if (result == 2) // The key does not exist.
return null;
throw new Win32Exception(result);
}
throw new PlatformNotSupportedException("The platform or operating system must be Windows XP or later.");
}
}
示例用法:
var key64 = RegistryExtensions.OpenBaseKey(RegistryHive.LocalMachine, RegistryExtensions.RegistryHiveType.X64);
var key32 = RegistryExtensions.OpenBaseKey(RegistryHive.LocalMachine, RegistryExtensions.RegistryHiveType.X86);
对于版本4之前的.NET版本,没有允许访问备用注册表视图的框架API。为了访问备用视图,您必须调用本机API RegOpenKeyEx
,并根据需要传递KEY_WOW64_32KEY
或KEY_WOW64_64KEY
标志之一。
常见的方法是使用C++/CLI混合模式程序集,或使用p/Invoke。然而,这一点也不好玩。注册表API使用起来比较困难,因为它们支持值的多种数据类型。
确定所需注册表的目标:
RegistryKey localMachine = Registry.LocalMachine; //For example
并获得您需要的价值:
RegistryKey lKey = localMachine.OpenSubKey(@"SOFTWARE'...'", false);