What are some alternatives to RegistryKey.OpenBaseKey in .NET 3.5?

后端 未结 3 1994
迷失自我
迷失自我 2020-11-30 12:35

I\'ve been working on an installer package and using RegistryKey.OpenBaseKey to work with custom actions that either open and add/remove keys to/from the 64-bit registry or

相关标签:
3条回答
  • 2020-11-30 13:15

    For .NET versions earlier than version 4 there is no framework API that allows access to alternate registry views. In order to access alternate views you must call the native API RegOpenKeyEx passing one of the KEY_WOW64_32KEY or KEY_WOW64_64KEY flags as appropriate.

    Common ways to do this are with C++/CLI mixed mode assemblies, or using P/Invoke. However, this is not very much fun at all. The registry APIs are some of the more awkward to use, because they support multiple data types for values.

    0 讨论(0)
  • 2020-11-30 13:19

    For anyone who is interested in a C# solution for some of the previous versions of .NET in order to not have to refactor too much code, its not pretty but here it is, totally doable using reflection. I found this trick in the XSharper source code.

    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.");
        }
    }
    

    Example usage:

    var key64 = RegistryExtensions.OpenBaseKey(RegistryHive.LocalMachine, RegistryExtensions.RegistryHiveType.X64);
    var key32 = RegistryExtensions.OpenBaseKey(RegistryHive.LocalMachine, RegistryExtensions.RegistryHiveType.X86);
    
    0 讨论(0)
  • 2020-11-30 13:29

    Targeting needed registry:

    RegistryKey localMachine = Registry.LocalMachine; //For example
    

    and get the value that you need:

    RegistryKey lKey = localMachine.OpenSubKey(@"SOFTWARE\...\", false);
    
    0 讨论(0)
提交回复
热议问题