.NET 3.5 中 RegistryKey.OpenBaseKey 的替代品有哪些? [英] What are some alternatives to RegistryKey.OpenBaseKey in .NET 3.5?

查看:34
本文介绍了.NET 3.5 中 RegistryKey.OpenBaseKey 的替代品有哪些?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在开发安装程序包并使用 RegistryKey.OpenBaseKey 与自定义操作一起使用,这些操作可以从 MSI 包的 64 位注册表或 32 位注册表中打开和添加/删除密钥,但这需要我在运行我的安装程序之前在目标机器上安装 .NET Framework 4,使用引导程序或其他东西,因为 OpenBaseKey 仅在 .NET Framework 4 中引入.理想情况下,我只想将 .NET Framework 3.5 并且仍然能够像 OpenBaseKey 那样修改 64 位或 32 位注册表配置单元;那么我就不需要 .NET 4 和安装它的开销了.

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 the 32-bit registry from an MSI package, but this requires me to install .NET Framework 4 on the target machine before running my installer, using a bootstrapper or something else, because OpenBaseKey was only introduced in .NET Framework 4. Ideally, I would like to target just .NET Framework 3.5 and still be able to modify either the 64-bit or 32-bit registry hives like in OpenBaseKey; then I wouldn't need .NET 4 and the overhead of installing it.

对于我们这些不想让 .NET 4 成为先决条件的人,是否有 OpenBaseKey 的替代方案?像 P/Invoking 某个 WinAPI 方法来启动它,也许?我不确定需要什么.

Are there alternatives to OpenBaseKey for those of us who would not like to make .NET 4 a prerequisite? Something like P/Invoking a certain WinAPI method to kick this off, perhaps? I'm not sure what it would take.

推荐答案

对于那些对某些以前版本的 .NET 的 C# 解决方案感兴趣的人来说,为了不必重构太多代码,它并不漂亮但是在这里,完全可以使用反射.我在 XSharper 源代码.

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

示例用法:

var key64 = RegistryExtensions.OpenBaseKey(RegistryHive.LocalMachine, RegistryExtensions.RegistryHiveType.X64);
var key32 = RegistryExtensions.OpenBaseKey(RegistryHive.LocalMachine, RegistryExtensions.RegistryHiveType.X86);

这篇关于.NET 3.5 中 RegistryKey.OpenBaseKey 的替代品有哪些?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆