我有一个注册表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应用程序中使用它,则代码将失败。因此,我仍然希望找到另一种适用于混合环境的解决方案。
答案 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);