32bit uygulamadan 64bit Registry okuma


100

AnyCPU için derlenmiş ac # birim test projem var. Derleme sunucumuz 64bit bir makinedir ve 64bit SQL Express örneğine sahiptir.

Test projesi, .MDF dosyalarının yolunu tanımlamak için aşağıdakine benzer bir kod kullanır:

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();
}

Bu kod, 32bit iş istasyonlarımızda iyi çalışıyor ve yakın zamanda NCover ile kod kapsamı analizini etkinleştirene kadar yapı sunucusunda iyi çalıştı. NCover, 32 bitlik bir COM bileşeni kullandığından, test çalıştırıcısı (Gallio) 32 bitlik bir işlem olarak çalışır.

Kayıt defteri kontrol edildiğinde, altında "Örnek Adları" anahtarı yok

HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Microsoft SQL Server

32 bit modunda çalışan bir uygulamanın kayıt defterine Wow6432Node dışında erişmesinin bir yolu var mı?

Yanıtlar:


21

kayıt defteri anahtarını oluştururken / açarken KEY_WOW64_64KEY parametresini kullanmanız gerekir. Ancak AFAIK, Registry sınıfıyla mümkün değildir, yalnızca API'yi doğrudan kullanırken mümkündür.

Bu , başlamanıza yardımcı olabilir.


152

64 bit Windows altında .NET Framework 4.x kullanan kayıt defteri erişimi için hala yerel destek vardır . Aşağıdaki kod Windows 7, 64 bit   ve ayrıca Windows 10, 64 bit ile   test edilmiştir   .

"Wow6432Node"Bir kayıt ağacını diğeriyle eşleyerek sanal olarak orada görünmesini sağlayan bir düğümü taklit eden kullanmak yerine , aşağıdaki işlemi yapabilirsiniz:

64 bit veya 32 bit kayıt defterine erişmeniz gerekip gerekmediğine karar verin ve aşağıda açıklandığı gibi kullanın. Her iki düğümden de kayıt defteri anahtarlarını tek bir sorguda almak için bir birleşim sorgusu oluşturan daha sonra bahsettiğim kodu (Ek bilgiler bölümü) de kullanabilirsiniz - böylece gerçek yollarını kullanarak onları yine de sorgulayabilirsiniz.

64 bit kayıt defteri

64 bit kayıt defterine erişmek için RegistryView.Registry64aşağıdakileri kullanabilirsiniz :

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 bit kayıt

32bit kayıt defterine erişmek istiyorsanız , RegistryView.Registry32aşağıdakileri kullanın :

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));

Kafanız karışmasın, her iki sürüm de Microsoft.Win32.RegistryHive.LocalMachineilk parametre olarak kullanılıyor , 2. parametreye göre 64 bit mi yoksa 32 bit mi kullanılacağını ayırt edersiniz ( tersi ).RegistryView.Registry64RegistryView.Registry32

Unutmayın ki

  • 64 bit Windows'ta, HKEY_LOCAL_MACHINE\Software\Wow6432Node64 bit sistemde çalışan 32 bit uygulamalar tarafından kullanılan değerleri içerir. Yalnızca gerçek 64 bit uygulamalar değerlerini HKEY_LOCAL_MACHINE\Softwaredoğrudan içinde depolar . Alt ağaç Wow6432Node, 32 bit uygulamalar için tamamen şeffaftır, 32 bit uygulamalar hala HKEY_LOCAL_MACHINE\Softwarebekledikleri gibi görür (bu bir tür yeniden yönlendirme). Windows'un eski sürümlerinde ve 32 bit Windows 7'de (ve Vista 32 bit) alt ağaç Wow6432Nodeaçıkça mevcut değildir .

  • Windows 7'deki (64 bit) bir hata nedeniyle, 32 bit kaynak kodu sürümü, hangi kuruluşu kaydetmiş olursanız olun her zaman "Microsoft" döndürürken, 64 bit kaynak kodu sürümü doğru kuruluşu döndürür.

Sağladığınız örneğe dönersek, 64 bitlik dala erişmek için aşağıdaki yolu izleyin:

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");

Ek bilgiler - pratik kullanım için:

Johny Skovdal'ın yorumlarda önerdiği ilginç bir yaklaşımı eklemek istiyorum , yaklaşımını kullanarak bazı yararlı işlevler geliştirmek için seçtiğim: Bazı durumlarda, 32 bit veya 64 bit. SQL örnek adları böyle bir örnektir. Bu durumda aşağıdaki gibi bir birleşim sorgusu kullanabilirsiniz (C # 6 veya üstü):

// 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);
}

Artık yukarıdaki işlevleri aşağıdaki gibi kullanabilirsiniz:

Örnek 1: SQL örnek adlarını alın

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}");
}

size sqlRegPath'deki değer adlarının ve değerlerinin bir listesini verecektir.

Not: Yukarıdaki ilgili işlevlerde parametreyi atlarsanız, bir tuşun varsayılan değerine (komut satırı aracı tarafından görüntülendiği REGEDT32.EXEgibi (Default)) erişebilirsiniz ValueName.

Bir kayıt defteri anahtarındaki Alt Anahtarların listesini almak için , GetRegKeyNamesveya işlevini kullanın GetAllRegKeyNames. Kayıt defterinde daha fazla anahtar arasında geçiş yapmak için bu listeyi kullanabilirsiniz.

Örnek 2: Yüklü yazılımın kaldırma bilgilerini alın

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

tüm 32 bit ve 64 bit kaldırma anahtarlarını alacaktır.

SQL sunucusu 32 bit veya 64 bit olarak kurulabildiğinden (yukarıdaki Örnek 1) işlevlerde gereken boş işlemeye dikkat edin . Fonksiyonlar aşırı yüklenmiştir, bu nedenle gerekirse 32 bit veya 64 bit parametresini geçebilirsiniz - ancak, atlarsanız 64 bit okumaya çalışır, bu başarısız olursa (boş değer), 32 bit değerleri okur.

Burada bir özellik var: GetAllRegValueNamesGenellikle bir döngü bağlamında kullanıldığından (yukarıdaki Örnek 1'e bakın), döngüleri nullbasitleştirmek yerine boş bir numaralandırılabilir döndürür foreach: bu şekilde ele alınmayacaksa, döngünün önekinin alınması gerekir bunu yapmak zahmetli olan bir ififadeyi kontrol etmek null- böylece işlevde bir kez ele alınır.

Neden boş hakkında endişeleniyorsun? Çünkü umursamazsanız, kodunuzda bu boş referans istisnasının neden atıldığını bulmak için çok daha fazla baş ağrınız olur - bunun nerede ve neden olduğunu bulmak için çok zaman harcarsınız. Ve eğer üretimde olduysa, günlük dosyalarını veya olay günlüklerini incelemekle çok meşgul olacaksınız (umarım günlüğe kaydetme uygulamışsınızdır) ... savunmaya yönelik bir şekilde yapabileceğiniz boş sorunlardan daha iyi kaçının. Operatörler ?., ?[... ]ve ??size çok yardımcı olabilir (yukarıda verilen koda bakın). Okumayı tavsiye ettiğim C # ' da yeni null atanabilir referans türlerini tartışan ve ayrıca bu Elvis operatörü hakkında güzel bir makale var .


İpucu: Windows altında tüm örnekleri test etmek için Linqpad'in ücretsiz sürümünü kullanabilirsiniz . Kurulum gerektirmez. Ad alanı içe aktarma sekmesine basıp F4girmeyi unutmayın Microsoft.Win32. Visual Studio'da, using Microsoft.Win32;kodunuzun en üstünde olması gerekir.

İpucu: Yeni tanımak için boş taşıma operatörleri , LINQPad aşağıdaki kodu denemek (ve hata ayıklama):

Örnek 3: Boş işleme operatörlerini gösterme

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 fiddle ile deneyin

İlgileniyorsanız, işte araçla başka neler yapabileceğinizi gösteren bir araya getirdiğim bazı örnekler.


2
Bu kapsamlı cevap için teşekkürler. Hafızamdan, soruyu gönderirken .NET 3.5 kullandığımı düşünüyorum, ancak .NET 4'ün durumu iyileştirdiğini görmek güzel
David Gardiner

2
Rica ederim. Son zamanlarda 64 bit kayıt defteri ile daha önce çözdüğüm benzer bir sorun yaşadım, bu yüzden çözümü paylaşmaya değer olduğunu düşündüm.
Matt

2
Bu tam olarak aradığım şey. Bunu 9.1 pencerelerinde yapıyorum ve harika çalışıyor.
Michiel Bugher

1
@AZ_ - düzenleme için teşekkürler, haklısın, anahtarın kapatılması gerekiyor!
Matt

1
@JohnySkovdal - Konuyu daha derine inmek isteyenler için sadece ek (isteğe bağlı) bilgi sağladığımı açıkça belirtmek için başlığı değiştirdim.
Matt

6

Yorum yapacak yeterli temsilcim yok, ancak OpenRemoteBaseKey kullanarak uzak bir kayıt defteri açarken çalıştığını belirtmek gerekir. RegistryView.Registry64 parametresinin eklenmesi, Makine A'daki 32 bitlik bir programın B Makinesi'ndeki 64 bitlik kayıt defterine erişmesine izin verir. Bu parametreyi geçmeden önce, programım OpenRemoteBaseKey'den sonra 32 bit okuyordu ve I anahtarını bulamadı sonraydı.

Not: Testimde, uzaktaki makine aslında benim makinemdi, ancak ona tıpkı farklı bir makinede olduğu gibi OpenRemoteBaseKey aracılığıyla eriştim.


4

bunu deneyin (32 bit işlemden):

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

( burada buldum ).


1
Güzel ipucu, kayıt defterini toplu olarak değiştirmenize izin verir. reg.exe /?Daha fazla bilgi almak için kullanın ...
Matt

4

NET 4'ü bununla birlikte kullanamıyorsanız RegistryKey.OpenBaseKey(..., RegistryView.Registry64), doğrudan Windows API kullanmanız gerekir.

Minimal birlikte çalışma şuna benzer:

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);

Şunun gibi kullanın:

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

Okuduklarımdan ve kendi testlerimden, bana öyle geliyor ki kayıt defteri "SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" yolunda kontrol edilmelidir. Çünkü diğer yollarda program kaldırıldıktan sonra kayıtlar silinmez.

Bu şekilde 32 bit yapılandırmalı 64 yazmaç elde ettim.

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 kayıt için:

registryKey = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
key = Registry.LocalMachine.OpenSubKey(registryKey);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.