Существует еще нативная поддержка доступа реестра в 64 - разрядной ОС Windows с использованием .NET Framework 4.x . Следующий код протестирован с Windows 7, 64 бит, а также с Windows 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-битную версию по второму параметру (по RegistryView.Registry64
сравнению с RegistryView.Registry32
).
Обратите внимание, что
В 64-битной Windows HKEY_LOCAL_MACHINE\Software\Wow6432Node
содержит значения, используемые 32-битными приложениями, работающими в 64-битной системе. Только настоящие 64-битные приложения хранят свои значения HKEY_LOCAL_MACHINE\Software
напрямую. Поддерево Wow6432Node
полностью прозрачно для 32-битных приложений, 32-битные приложения по-прежнему видят то, HKEY_LOCAL_MACHINE\Software
что ожидают (это своего рода перенаправление). В более старых версиях Windows, а также в 32-битной Windows 7 (и 32-битной Vista) поддерево Wow6432Node
явно не существует.
Из-за ошибки в Windows 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)?.GetValueNames();
}
public static IEnumerable<string> GetAllRegValueNames(string RegPath,
RegistryHive hive = RegistryHive.LocalMachine)
{
var reg64 = GetRegValueNames(RegistryView.Registry64, RegPath, hive);
var reg32 = GetRegValueNames(RegistryView.Registry32, 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)?.GetValue(ValueName);
}
public static object GetRegValue(string RegPath, string ValueName="",
RegistryHive hive = RegistryHive.LocalMachine)
{
return GetRegValue(RegistryView.Registry64, RegPath, ValueName, hive)
?? GetRegValue(RegistryView.Registry32, 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.Registry32, 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
параметр в соответствующих функциях выше.
Чтобы получить список вложенных ключей в разделе реестра, используйте функцию 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
которых будет обременительной необходимости сделать это - так , что рассматривается один раз в функции.
Зачем беспокоиться о нуле? Потому что, если вам все равно, у вас будет намного больше головной боли, выясняя, почему в вашем коде было выбрано исключение с нулевой ссылкой - вы потратите много времени на выяснение, где и почему это произошло. И если это произошло в производственной среде, вы будете очень заняты изучением файлов журналов или журналов событий (я надеюсь, что у вас реализовано ведение журналов) ... лучше избегать нулевых проблем, если это можно сделать защитным способом. Операторы ?.
, ?[
... ]
и ??
могут вам очень помочь (см. Приведенный выше код). Есть хорошая связанная статья, в которой обсуждаются новые ссылочные типы, допускающие значение NULL, в C # , которую я рекомендую прочитать, а также эта статья об операторе Элвиса.
Подсказка: вы можете использовать бесплатную версию Linqpad для тестирования всех примеров под Windows. Не требует установки. Не забудьте нажать F4и войти Microsoft.Win32
на вкладку импорта пространства имен. В Visual Studio требуется, using Microsoft.Win32;
чтобы в верхней части кода.
Совет: чтобы познакомиться с новыми операторами обработки null , попробуйте (и отладьте) следующий код в LinqPad:
Пример 3: Демонстрация операторов обработки null
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
Если вам интересно, вот несколько примеров, которые я собрал, показывающих, что еще вы можете делать с этим инструментом.