.NET 3.5中的RegistryKey.OpenBaseKey有哪些替代方法?

我一直在使用安装程序包并使用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#解决方案感兴趣的人来说,为了不必重构太多的代码,它不是很漂亮,但在这里,完全可以使用reflection。 我在XSharper源代码中发现了这个技巧。

public static class RegistryExtensions { public enum RegistryHiveType { X86, X64 } static Dictionary _hiveKeys = new Dictionary { { 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 _accessMasks = new Dictionary { { 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_32KEYKEY_WOW64_64KEY标志之一。

常见的方法是使用C ++ / CLI混合模式程序集,或使用P / Invoke 。 但是,这根本不是很有趣。 注册表API更难以使用,因为它们支持值的多种数据类型。