2014-10-06 6 views
8

Ich habe an einem Installationspaket gearbeitet und RegistryKey.OpenBaseKey verwendet, um mit benutzerdefinierten Aktionen zu arbeiten, die Schlüssel zu/von der 64-Bit-Registrierung oder der 32-Bit-Registrierung von einem MSI-Paket öffnen und entfernen/entfernen, aber dies erfordert mich Installieren Sie .NET Framework 4 auf dem Zielcomputer, bevor Sie mein Installationsprogramm ausführen, indem Sie einen Bootstrapper oder etwas anderes verwenden, da OpenBaseKey nur in .NET Framework 4 eingeführt wurde. Im Idealfall möchte ich nur .NET Framework 3.5 als Ziel haben in der Lage, entweder die 64-Bit- oder die 32-Bit-Registrierungsstruktur wie in OpenBaseKey zu ändern; dann würde ich .NET 4 und den Overhead der Installation nicht brauchen.Was sind einige Alternativen zu RegistryKey.OpenBaseKey in .NET 3.5?

Gibt es Alternativen zu OpenBaseKey für diejenigen von uns, die nicht möchten, dass .NET 4 eine Voraussetzung ist? So etwas wie P/Aufrufen einer bestimmten WinAPI-Methode, um das vielleicht abzustoßen? Ich bin mir nicht sicher, was es brauchen würde.

Antwort

13

Für alle, die an einer C# -Lösung für einige der vorherigen Versionen von .NET interessiert sind, um nicht zu viel Code umgestalten zu müssen, ist es nicht schön, aber hier ist es völlig möglich mit Reflektion. Ich fand diesen Trick in der 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."); 
    } 
} 

Beispiel Nutzung:

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

Das ist großartig. Ich wünschte, ich könnte dir mehr Punkte geben. –

+0

@BlackFrog Schön, dass es meinen Kollegen hilft :) – Alexandru

+0

Super Code! Danke für die Hilfe. Es scheint jedoch, dass es einen Unterschied zwischen dem Code und den Kommentaren gibt. Wenn es wirklich für "Windows 2000 und später" ist, denke ich, dass der Vergleich "Environment.OSVersion.Version.Major> = 5" sein sollte –

2

Für .NET-Versionen vor Version 4 gibt es keine Framework-API, die den Zugriff auf alternative Registrierungsansichten ermöglicht. Um auf alternative Ansichten zugreifen zu können, müssen Sie die native API RegOpenKeyEx aufrufen, indem Sie je nach Bedarf eines der Flags KEY_WOW64_32KEY oder KEY_WOW64_64KEY übergeben.

Die gängigsten Methoden hierfür sind C++/CLI-Mixed-Mode-Assemblys oder P/Invoke. Das macht aber überhaupt nicht viel Spaß. Die Registrierungs-APIs sind etwas schwieriger zu verwenden, da sie mehrere Datentypen für Werte unterstützen.