एक 32 बिट अनुप्रयोग से 64 बिट रजिस्ट्री पढ़ना


98

मेरे पास एसी # यूनिट टेस्ट प्रोजेक्ट है जो AnyCPU के लिए संकलित है। हमारा बिल्ड सर्वर 64 बिट मशीन है, और इसमें 64 बिट एसक्यूएल एक्सप्रेस इंस्टाल इंस्टाल है।

परीक्षण प्रोजेक्ट .MDF फ़ाइलों के लिए पथ की पहचान करने के लिए निम्न के समान कोड का उपयोग करता है:

    private string GetExpressPath()
    {
        RegistryKey sqlServerKey = Registry.LocalMachine.OpenSubKey( @"SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL" );
        string sqlExpressKeyName = (string) sqlServerKey.GetValue( "SQLEXPRESS" );
        RegistryKey sqlInstanceSetupKey = sqlServerKey.OpenSubKey( sqlExpressKeyName + @"\Setup" );
        return sqlInstanceSetupKey.GetValue( "SQLDataRoot" ).ToString();
    }

यह कोड हमारे 32 बिट वर्कस्टेशन पर ठीक काम करता है, और मैंने हाल ही में NCover के साथ कोड कवरेज विश्लेषण को सक्षम करने तक बिल्ड सर्वर पर ठीक काम किया है। क्योंकि NCover 32bit COM घटक का उपयोग करता है, परीक्षण धावक (Gallio) एक 32bit प्रक्रिया के रूप में चलता है।

रजिस्ट्री की जाँच, के तहत कोई "इंस्टेंस नाम" कुंजी नहीं है

HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Microsoft SQL सर्वर

क्या Wow6432Node के बाहर रजिस्ट्री तक पहुंचने के लिए 32bit मोड में चलने वाले एप्लिकेशन का कोई तरीका है?

जवाबों:


21

रजिस्ट्री कुंजी बनाते / खोलते समय आपको KEY_WOW64_64KEY परम का उपयोग करना होगा। लेकिन AFAIK यह रजिस्ट्री वर्ग के साथ संभव नहीं है, लेकिन केवल एपीआई का सीधे उपयोग करते समय।

यह आपको आरंभ करने में मदद कर सकता है।


151

.NET फ्रेमवर्क 4.x का उपयोग करके 64 बिट विंडोज के तहत रजिस्ट्री एक्सेस के लिए अभी भी मूल समर्थन है । निम्न कोड का परीक्षण   विंडोज 7, 64 बिट   और विंडोज 10, 64 बिट के साथ भी किया जाता है   ।

उपयोग करने के बजाय "Wow6432Node", जो एक रजिस्ट्री पेड़ को दूसरे में मैप करके एक नोड का अनुकरण करता है, जिससे यह वास्तव में वहां दिखाई देता है, आप कर सकते हैं:

तय करें, आपको 64 बिट या 32 बिट रजिस्ट्री तक पहुंचने की आवश्यकता है या नहीं, और नीचे वर्णित के रूप में उपयोग करें। आप बाद में बताए गए कोड (अतिरिक्त सूचना अनुभाग) का भी उपयोग कर सकते हैं, जो एक क्वेरी में दोनों नोड्स से रजिस्ट्री कुंजी प्राप्त करने के लिए एक संघ क्वेरी बनाता है - इसलिए आप अभी भी उनके वास्तविक पथ का उपयोग करके उन्हें क्वेरी कर सकते हैं।

64 बिट रजिस्ट्री

64 बिट रजिस्ट्री तक पहुंचने के लिए , आप RegistryView.Registry64निम्नानुसार उपयोग कर सकते हैं :

string value64 = string.Empty; 
RegistryKey localKey = 
    RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, 
        RegistryView.Registry64); 
localKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"); 
if (localKey != null) 
{ 
    value64 = localKey.GetValue("RegisteredOrganization").ToString(); 
    localKey.Close();
} 
Console.WriteLine(String.Format("RegisteredOrganization [value64]: {0}",value64));

32 बिट रजिस्ट्री

यदि आप 32 बिट रजिस्ट्री का उपयोग करना चाहते हैं , तो RegistryView.Registry32निम्नानुसार उपयोग करें :

string value32 = string.Empty; 
RegistryKey localKey32 = 
    RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, 
        RegistryView.Registry32); 
localKey32 = localKey32.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"); 
if (localKey32 != null) 
{ 
    value32 = localKey32.GetValue("RegisteredOrganization").ToString(); 
    localKey32.Close();
} 
Console.WriteLine(String.Format("RegisteredOrganization [value32]: {0}",value32));

भ्रमित न हों, दोनों संस्करण Microsoft.Win32.RegistryHive.LocalMachineपहले पैरामीटर के रूप में उपयोग कर रहे हैं , आप यह अंतर करते हैं कि 64 बिट या 32 बिट को 2 पैरामीटर ( RegistryView.Registry64बनाम RegistryView.Registry32) का उपयोग करना है या नहीं ।

नोट है कि

  • 64 बिट विंडोज HKEY_LOCAL_MACHINE\Software\Wow6432Nodeपर, 64 बिट सिस्टम पर चलने वाले 32 बिट अनुप्रयोगों द्वारा उपयोग किए जाने वाले मान शामिल हैं। केवल सच्चे 64 बिट अनुप्रयोग HKEY_LOCAL_MACHINE\Softwareसीधे अपने मूल्यों को संग्रहीत करते हैं। सबट्री Wow6432Node32 बिट अनुप्रयोगों के लिए पूरी तरह से पारदर्शी है, 32 बिट एप्लिकेशन अभी भी देखते हैं HKEY_LOCAL_MACHINE\Softwareक्योंकि वे इसकी उम्मीद करते हैं (यह एक तरह का पुनर्निर्देशन है)। विंडोज के पुराने संस्करणों में और साथ ही 32 बिट विंडोज 7 (और विस्टा 32 बिट) में सबट्री Wow6432Nodeस्पष्ट रूप से मौजूद नहीं है।

  • विंडोज 7 (64 बिट) में एक बग के कारण, 32 बिट स्रोत कोड संस्करण हमेशा "Microsoft" देता है, भले ही आपने किस संगठन को पंजीकृत किया हो, जबकि 64 बिट स्रोत कोड संस्करण सही संगठन देता है।

आपके द्वारा दिए गए उदाहरण पर वापस आते हुए, इसे 64 बिट शाखा तक पहुँचने के लिए निम्न तरीके से करें:

RegistryKey localKey = 
    RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, 
        RegistryView.Registry64); 
RegistryKey sqlServerKey = localKey.OpenSubKey(
    @"SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL");
string sqlExpressKeyName = (string) sqlServerKey.GetValue("SQLEXPRESS");

अतिरिक्त जानकारी - व्यावहारिक उपयोग के लिए:

मैं एक दिलचस्प दृष्टिकोण जोड़ना चाहूंगा जॉनी स्कोवडल ने टिप्पणियों में सुझाव दिया है, जो मैंने उनके दृष्टिकोण का उपयोग करके कुछ उपयोगी कार्यों को विकसित करने के लिए उठाया है: कुछ स्थितियों में आप सभी कुंजियों को वापस प्राप्त करना चाहते हैं, चाहे वह 32 बिट हो या 64 बिट। SQL इंस्टेंस नाम ऐसे उदाहरण हैं। आप इस मामले में एक संघ क्वेरी का उपयोग इस प्रकार कर सकते हैं (C # 6 या उच्चतर):

// using Microsoft.Win32;
public static IEnumerable<string> GetRegValueNames(RegistryView view, string regPath,
                                  RegistryHive hive = RegistryHive.LocalMachine) 
{ 
    return RegistryKey.OpenBaseKey(hive, view)
                     ?.OpenSubKey(regPath)?.G‌​etValueNames();
}

public static IEnumerable<string> GetAllRegValueNames(string RegPath,
                                  RegistryHive hive = RegistryHive.LocalMachine) 
{
    var reg64 = GetRegValueNames(RegistryView.Registry64, RegPath, hive);
    var reg32 = GetRegValueNames(RegistryView.Re‌​gistry32, RegPath, hive);
    var result = (reg64 != null && reg32 != null) ? reg64.Union(reg32) : (reg64 ?? reg32);
    return (result ?? new List<string>().AsEnumerable()).OrderBy(x => x);
}

public static object GetRegValue(RegistryView view, string regPath, string ValueName="",
                                 RegistryHive hive = RegistryHive.LocalMachine)
{
    return RegistryKey.OpenBaseKey(hive, view)
                       ?.OpenSubKey(regPath)?.G‌​etValue(ValueName);
}

public static object GetRegValue(string RegPath, string ValueName="",
                                 RegistryHive hive = RegistryHive.LocalMachine)
{   
    return GetRegValue(RegistryView.Registry64, RegPath, ValueName, hive) 
                     ?? GetRegValue(RegistryView.Re‌​gistry32, RegPath, ValueName, hive);
}

public static IEnumerable<string> GetRegKeyNames(RegistryView view, string regPath,
                   RegistryHive hive = RegistryHive.LocalMachine)
{
    return RegistryKey.OpenBaseKey(hive, view)
        ?.OpenSubKey(regPath)?.GetSubKeyNames(); 
}

public static IEnumerable<string> GetAllRegKeyNames(string RegPath,
                                  RegistryHive hive = RegistryHive.LocalMachine)
{
    var reg64 = GetRegKeyNames(RegistryView.Registry64, RegPath, hive);
    var reg32 = GetRegKeyNames(RegistryView.Re‌​gistry32, RegPath, hive);
    var result = (reg64 != null && reg32 != null) ? reg64.Union(reg32) : (reg64 ?? reg32);
    return (result ?? new List<string>().AsEnumerable()).OrderBy(x => x);
}

अब आप बस ऊपर दिए गए कार्यों का उपयोग इस प्रकार कर सकते हैं:

उदाहरण 1: SQL आवृत्ति नाम प्राप्त करें

var sqlRegPath=@"SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL";
foreach (var valueName in GetAllRegValueNames(sqlRegPath))
{
    var value=GetRegValue(sqlRegPath, valueName);
    Console.WriteLine($"{valueName}={value}");
}

आपको sqlRegPath में मूल्य नामों और मूल्यों की एक सूची देगा।

नोट: आप उपयोग कर सकते हैं डिफ़ॉल्ट एक कुंजी के मूल्य (कमांडलाइन उपकरण द्वारा प्रदर्शित REGEDT32.EXEके रूप में (Default)अगर आप को छोड़ देते हैं) ValueNameके ऊपर इसी कार्यों में पैरामीटर।

एक रजिस्ट्री कुंजी के भीतर SubKeys की सूची प्राप्त करने के लिए , फ़ंक्शन का उपयोग करें GetRegKeyNamesया GetAllRegKeyNames। आप इस सूची का उपयोग रजिस्ट्री में आगे कीज़ को पार करने के लिए कर सकते हैं।

उदाहरण 2: स्थापित सॉफ़्टवेयर की स्थापना रद्द जानकारी प्राप्त करें

var currentVersionRegPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion";
var uninstallRegPath = $@"{currentVersionRegPath}\Uninstall";
var regKeys = Registry.GetAllRegKeyNames(RegPath: uninstallRegPath);

सभी 32 बिट और 64 बिट स्थापना रद्द कुंजी मिल जाएगा।

कार्यों में आवश्यक शून्य हैंडलिंग को नोटिस करें क्योंकि SQL सर्वर को 32 बिट या 64 बिट (उदाहरण 1 ऊपर) के रूप में स्थापित किया जा सकता है। कार्य अतिभारित होते हैं, इसलिए यदि आवश्यक हो तो आप अभी भी 32 बिट या 64 बिट पैरामीटर पास कर सकते हैं - हालांकि, यदि आप इसे छोड़ देते हैं तो यह 64 बिट पढ़ने की कोशिश करेगा, यदि यह विफल रहता है (शून्य मान), तो यह 32 बिट मानों को पढ़ता है।

यहाँ एक विशेषता है: क्योंकि GetAllRegValueNamesआमतौर पर एक लूप संदर्भ में उपयोग किया जाता है (उदाहरण 1 ऊपर देखें), यह छोरों nullको सरल बनाने के बजाय एक खाली स्थान देता foreachहै: यदि इसे इस तरह से संभाला नहीं जाता है, तो लूप को उपसर्ग करना होगा एक ifबयान की जाँच nullजिसके लिए बोझिल हो जाएगा - तो यह है कि समारोह में एक बार के साथ निपटा है।

अशक्त के बारे में क्यों परेशान? क्योंकि यदि आप परवाह नहीं करते हैं, तो आपको यह पता लगाने में बहुत अधिक सिरदर्द होंगे कि आपके कोड में उस अशक्त संदर्भ अपवाद को क्यों फेंका गया था - आपको यह पता लगाने में बहुत समय व्यतीत होगा कि यह कहां और क्यों हुआ। और अगर यह उत्पादन में हुआ है तो आप लॉग फाइल या ईवेंट लॉग का अध्ययन करने में बहुत व्यस्त होंगे (मुझे आशा है कि आपने लॉगिंग कार्यान्वित की है) ... बेहतर है कि आप एक रक्षात्मक तरीके से कर सकते हैं। ऑपरेटर ?., ?[... ]और ??आपकी बहुत मदद कर सकते हैं (ऊपर दिया गया कोड देखें)। वहाँ एक अच्छा संबंधित लेख नई चर्चा कर है सी # में नल संदर्भ प्रकार है, जो मैंने पढ़ा है और यह भी करने के लिए सलाह देते हैं यह एक एल्विस ऑपरेटर के बारे में।


संकेत: आप विंडोज के तहत सभी उदाहरणों का परीक्षण करने के लिए लिनकैप के मुफ्त संस्करण का उपयोग कर सकते हैं । यह एक स्थापना की आवश्यकता नहीं है। Namespace import टैब में प्रेस F4और एंटर करना न भूलें Microsoft.Win32। Visual Studio में, आपको using Microsoft.Win32;अपने कोड में सबसे ऊपर की आवश्यकता होती है ।

युक्ति: नए नल संचालकों से खुद को परिचित करने के लिए , LinqPad में निम्नलिखित कोड देखें (और डिबग करें):

उदाहरण 3: अशक्त हैंडलिंग ऑपरेटरों का प्रदर्शन

static string[] test { get { return null;} } // property used to return null
static void Main()
{
    test.Dump();                    // output: null
    // "elvis" operator:
    test?.Dump();                   // output: 
    // "elvis" operator for arrays
    test?[0].Dump();                // output: 
    (test?[0]).Dump();              // output: null
    // combined with null coalescing operator (brackets required):
    (test?[0]??"<null>").Dump();    // output: "<null>"
}

इसे .Net फ़िडेल के साथ आज़माएं

यदि आप रुचि रखते हैं, तो यहां कुछ उदाहरण दिए गए हैं जो मैं दिखा रहा हूं कि आप उपकरण के साथ और क्या कर सकते हैं।


2
उस व्यापक उत्तर के लिए धन्यवाद। स्मृति से मुझे लगता है कि मैं .NET 3.5 का उपयोग कर रहा था जब मैंने सवाल पोस्ट किया था, लेकिन .NET 4 को देखने के लिए स्थिति में सुधार हुआ है
डेविड गार्डिनर

2
आपका स्वागत है। मेरे पास 64 बिट रजिस्ट्री के साथ हाल ही में एक समस्या थी जो मैंने पहले ही हल कर ली थी, इसलिए मुझे लगा कि यह समाधान साझा करने के लायक है।
मैट

2
यह वही है जिसकी मुझे तलाश है। मैं विंडोज़ 9.1 में यह कर रहा हूँ और यह बहुत अच्छा काम करता है।
मिकिएल बुगर

1
@AZ_ - संपादन के लिए धन्यवाद, आप सही हैं, कुंजी को बंद करने की आवश्यकता है!
मैट

1
@ जॉनीसकोवडाल - मैंने यह स्पष्ट करने के लिए शीर्षक बदल दिया है कि मैं केवल अतिरिक्त (वैकल्पिक) जानकारी प्रदान कर रहा हूं - उन लोगों के लिए जो इस मामले में गहराई से खुदाई करना चाहते हैं।
मैट

6

मेरे पास टिप्पणी करने के लिए पर्याप्त प्रतिनिधि नहीं है, लेकिन यह इंगित करने योग्य है कि यह OpenRemoteBaseKey का उपयोग करके दूरस्थ रजिस्ट्री खोलते समय काम करता है। रजिस्ट्री दृश्य जोड़ना। रैगरिस्टी 64 पैरामीटर मशीन बी पर 64-बिट रजिस्ट्री तक पहुंचने के लिए मशीन ए पर 32-बिट प्रोग्राम की अनुमति देता है। इससे पहले कि मैं उस पैरामीटर को पास करूं, मेरा प्रोग्राम ओपनरैमोटबेस के बाद 32-बिट पढ़ रहा था, और मुझे कुंजी नहीं मिली। के बाद था।

नोट: मेरे परीक्षण में, रिमोट मशीन वास्तव में मेरी मशीन थी, लेकिन मैंने इसे OpenRemoteBaseKey के माध्यम से एक्सेस किया, जैसे मैं एक अलग मशीन के लिए करूंगा।


4

इसे आज़माएँ (एक 32 बिट प्रक्रिया से):

> %WINDIR%\sysnative\reg.exe query ...

(पाया कि यहाँ )।


1
अच्छा संकेत, यह एक बैच में रजिस्ट्री में हेरफेर करने की अनुमति देता है। reg.exe /?अधिक जानकारी प्राप्त करने के लिए उपयोग करें ...
मैट

4

यदि आप इसके साथ .NET 4 का उपयोग नहीं कर सकते हैं RegistryKey.OpenBaseKey(..., RegistryView.Registry64), तो आपको सीधे विंडोज एपीआई का उपयोग करने की आवश्यकता है।

न्यूनतम इंटरोप जैसा है:

internal enum RegistryFlags
{
    ...
    RegSz = 0x02,
    ...
    SubKeyWow6464Key = 0x00010000,
    ...
}

internal enum RegistryType
{
    RegNone = 0,
    ...
}

[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int RegGetValue(
    UIntPtr hkey, string lpSubKey, string lpValue, RegistryFlags dwFlags, 
    out RegistryType pdwType, IntPtr pvData, ref uint pcbData);

इसका उपयोग करें जैसे:

IntPtr data = IntPtr.Zero;
RegistryType type;
uint len = 0;
RegistryFlags flags = RegistryFlags.RegSz | RegistryFlags.SubKeyWow6464Key;
UIntPtr key = (UIntPtr)((uint)RegistryHive.LocalMachine);

const string subkey= @"SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL";
const string value = "SQLEXPRESS";

if (RegGetValue(key, subkey, value, flags, out type, data, ref len) == 0)
{
    data = Marshal.AllocHGlobal((int)len);
    if (RegGetValue(key, subkey, value, flags, out type, data, ref len) == 0)
    {
        string sqlExpressKeyName = Marshal.PtrToStringUni(data);
    }
}

0

मैंने जो भी पढ़ा है और अपने स्वयं के परीक्षणों से, यह मुझे लगता है कि रजिस्ट्री को इस रास्ते में "सॉफ़्टवेयर \ Microsoft \ Windows \ CurrentVersion \ Uninstall" की जाँच करनी चाहिए। क्योंकि अन्य रास्तों में प्रोग्राम को अनइंस्टॉल करने के बाद रजिस्टर डिलीट नहीं किए जाते हैं।

इस तरह मुझे 32 बिट कॉन्फ़िगरेशन के साथ 64 रजिस्टर मिले।

string registryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
RegistryKey key64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey key = key64.OpenSubKey(registryKey);
if (key != null)
{
    var list = key.GetSubKeyNames().Select(keyName => key.OpenSubKey(keyName).GetValue("DisplayName")).ToList();

    key.Close();
}

32 रजिस्टर के लिए है:

registryKey = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
key = Registry.LocalMachine.OpenSubKey(registryKey);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.