将HKEY转换为Microsoft.Win32.RegistryKey

时间:2014-01-17 19:45:22

标签: c# windows winapi registry c#-2.0

我有一个注册表HKEY,它与RegOpenKeyEx(WinApi)一起开放。现在我想将HKEY转换为对象Microsoft.Win32.RegistryKey。这将允许我使用更方便的.Net操作来进一步继续使用此密钥。

你知道如何以可靠的方式为C#.Net 2.0做更高的转换吗?

感谢您的帮助!

我尝试使用反射来访问RegistryKey.GetBaseKey(hKey),以便从HKEY转换为RegistryKey,但是失败了:

[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(IntPtr hKey, string subKey, int ulOptions, int samDesired, out IntPtr phkResult);

public enum RegWow64Options
{
    None = 0,
    KEY_WOW64_64KEY = 0x0100,
    KEY_WOW64_32KEY = 0x0200
}

public enum RegRights
{
    ReadKey = 131097,
    WriteKey = 131078
}

static void exampleTransformKeytoRegistryKey()
{
    IntPtr hKeyChild;
    IntPtr hKeyParent = getRegistryKeyHandle(Registry.LocalMachine);

    if (hKeyParent != IntPtr.Zero)
    {
        int result = RegOpenKeyEx(
            getRegistryKeyHandle(Registry.LocalMachine),
            @"SOFTWARE\Microsoft",
            0,
            ((int)RegRights.ReadKey) | ((int)RegWow64Options.KEY_WOW64_64KEY),
            out hKeyChild);

        if (result == 0)
        {
            // hKeyChild has been retrieved
            // now convert hKeyChild to RegistryKey keyChild

            Type keyType = typeof(RegistryKey);
            RegistryKey keyChild = (RegistryKey)keyType.InvokeMember(
                "GetBaseKey",
                System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static,
                null,
                keyType,
                new object[] { hKeyChild });

            // work with keyChild...
        }
    }
}

static IntPtr getRegistryKeyHandle(RegistryKey registryKey)
{
    Type registryKeyType = typeof(RegistryKey);
    System.Reflection.FieldInfo fieldInfo =
        registryKeyType.GetField("hkey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

    SafeHandle handle = (SafeHandle)fieldInfo.GetValue(registryKey);
    IntPtr dangerousHandle = handle.DangerousGetHandle();
    return dangerousHandle;
}

更新:以下方法将起作用(在某种程度上)。请关注函数getKeyToRegistryKey。

[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(IntPtr hKey, string subKey, int ulOptions, int samDesired, out IntPtr phkResult);

public enum RegWow64Options
{
    None = 0,
    KEY_WOW64_64KEY = 0x0100,
    KEY_WOW64_32KEY = 0x0200
}

public enum RegRights
{
    ReadKey = 131097,
    WriteKey = 131078
}

static void exampleTransformKeytoRegistryKey2()
{
    IntPtr hKeyChild;
    IntPtr hKeyParent = getRegistryKeyHandle(Registry.LocalMachine);

    if (hKeyParent != IntPtr.Zero)
    {
        int result = RegOpenKeyEx(
            getRegistryKeyHandle(Registry.LocalMachine),
            @"SOFTWARE\Microsoft",
            0,
            ((int)RegRights.ReadKey) | ((int)RegWow64Options.KEY_WOW64_32KEY),
            out hKeyChild);

        if (result == 0)
        {
            // hKeyChild has been retrieved
            // now convert hKeyChild to RegistryKey keyChild
            RegistryKey keyChild = getKeyToRegistryKey(hKeyChild, false, true);

            // work with keyChild...
        }
    }
}

static RegistryKey getKeyToRegistryKey(IntPtr hKey, bool writable, bool ownsHandle)
{
    //Get the BindingFlags for private contructors
    System.Reflection.BindingFlags privateConstructors = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic;
    //Get the Type for the SafeRegistryHandle
    Type safeRegistryHandleType = typeof(Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid).Assembly.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle");
    //Get the array of types matching the args of the ctor we want
    Type[] safeRegistryHandleCtorTypes = new Type[] { typeof(IntPtr), typeof(bool) };
    //Get the constructorinfo for our object
    System.Reflection.ConstructorInfo safeRegistryHandleCtorInfo = safeRegistryHandleType.GetConstructor(
            privateConstructors, null, safeRegistryHandleCtorTypes, null);
    //Invoke the constructor, getting us a SafeRegistryHandle
    Object safeHandle = safeRegistryHandleCtorInfo.Invoke(new Object[] { hKey, ownsHandle });

    //Get the type of a RegistryKey
    Type registryKeyType = typeof(RegistryKey);
    //Get the array of types matching the args of the ctor we want
    Type[] registryKeyConstructorTypes = new Type[] { safeRegistryHandleType, typeof(bool) };
    //Get the constructorinfo for our object
    System.Reflection.ConstructorInfo registryKeyCtorInfo = registryKeyType.GetConstructor(
        privateConstructors, null, registryKeyConstructorTypes, null);
    //Invoke the constructor, getting us a RegistryKey
    RegistryKey resultKey = (RegistryKey)registryKeyCtorInfo.Invoke(new Object[] { safeHandle, writable });
    //return the resulting key
    return resultKey;
}

static IntPtr getRegistryKeyHandle(RegistryKey registryKey)
{
    Type registryKeyType = typeof(RegistryKey);
    System.Reflection.FieldInfo fieldInfo =
    registryKeyType.GetField("hkey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

    SafeHandle handle = (SafeHandle)fieldInfo.GetValue(registryKey);
    IntPtr dangerousHandle = handle.DangerousGetHandle();
    return dangerousHandle;
}

这种方法的问题在于它只适用于纯.Net 2.0应用程序。如果您使用.Net 2.0 DLL中的代码并尝试从.Net 4.0应用程序中使用它,则代码将失败。因此,我仍然希望找到另一种适用于混合环境的解决方案。

3 个答案:

答案 0 :(得分:4)

使用RegistryKey.FromHandle(new SafeRegistryHandle(handle,true));

答案 1 :(得分:2)

鉴于你的目标是.net 2,根本没有出路。你需要一直p /调用它。如果您使用的是.net 4,那么您根本不需要任何p / invoke,因为您可以使用RegistryView枚举。但对于.net 2,唯一的选择是p / invoke本机注册表API。

答案 2 :(得分:0)

它不漂亮,但它完全可以使用反射。我在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 2000 or later.");
    }
}

使用示例:

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