2014-10-06 7 views
8

मैं एक इंस्टॉलर पैकेज पर काम कर रहा हूं और कस्टम क्रियाओं के साथ काम करने के लिए RegistryKey.OpenBaseKey का उपयोग कर रहा हूं जो या तो 64-बिट रजिस्ट्री से या किसी एमएसआई पैकेज से 32-बिट रजिस्ट्री से/खोलें/हटाएं, लेकिन इसके लिए मुझे आवश्यकता है बूटस्ट्रैपर या कुछ और का उपयोग करके, मेरे इंस्टॉलर को चलाने से पहले लक्ष्य मशीन पर .NET Framework 4 स्थापित करने के लिए, क्योंकि ओपनबेससे केवल .NET Framework 4 में पेश किया गया था। आदर्श रूप में, मैं केवल .NET Framework 3.5 को लक्षित करना चाहता हूं और अभी भी ओपनबेससे में 64-बिट या 32-बिट रजिस्ट्री हाइव को संशोधित करने में सक्षम; तो मुझे .NET 4 और इसे इंस्टॉल करने के ऊपरी हिस्से की आवश्यकता नहीं होगी।.NET 3.5 में RegistryKey.OpenBaseKey के कुछ विकल्प क्या हैं?

क्या हम उन लोगों के लिए ओपनबेससे के विकल्प हैं जो .NET 4 को एक पूर्व शर्त बनाना नहीं चाहते हैं? कुछ ऐसा करने के लिए पी/कुछ निश्चित WinAPI विधि को आमंत्रित करना, शायद? मुझे यकीन नहीं है कि यह क्या होगा।

उत्तर

13

किसी भी व्यक्ति के लिए जो .NET के पिछले कुछ संस्करणों के लिए सी # समाधान में दिलचस्पी रखने के लिए बहुत अधिक कोड को दोबारा करने के लिए नहीं है, यह सुंदर नहीं है लेकिन यहां यह प्रतिबिंब का उपयोग करके पूरी तरह से करने योग्य है। मुझे यह चाल 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); 
+1

यह बहुत अच्छा है। काश मैं आपको अधिक अंक दे सकता हूं। –

+0

@ ब्लैकफ्रोग खुशी है यह मेरे साथी देवताओं की मदद करता है :) – Alexandru

+0

बहुत बढ़िया कोड! सहायता के लिए धन्यवाद। ऐसा लगता है कि हालांकि कोड और टिप्पणियों के बीच एक मेल नहीं है। यदि यह वास्तव में "विंडोज 2000 और बाद में" के लिए है, तो मुझे लगता है कि तुलना "पर्यावरण .OSVersion.Version.Major> = 5" –

2

संस्करण 4 से पहले .NET संस्करणों के लिए कोई फ्रेमवर्क API नहीं है जो वैकल्पिक रजिस्ट्री दृश्यों तक पहुंच की अनुमति देता है। वैकल्पिक विचारों तक पहुंचने के लिए आपको मूल एपीआई RegOpenKeyEx को KEY_WOW64_32KEY या KEY_WOW64_64KEY फ़्लैग को उचित रूप से पास करना होगा।

ऐसा करने के सामान्य तरीके सी ++/सीएलआई मिश्रित मोड असेंबली के साथ हैं, या P/Invoke का उपयोग कर रहे हैं। हालांकि, यह बिल्कुल बहुत मजेदार नहीं है। रजिस्ट्री एपीआई उपयोग करने के लिए कुछ अधिक अजीब हैं, क्योंकि वे मानों के लिए एकाधिक डेटा प्रकारों का समर्थन करते हैं।

संबंधित मुद्दे