Há ainda suporte nativo para acesso ao registro em 64 bits do Windows usando o .NET Framework 4.x . O código a seguir foi testado com Windows 7 de 64 bits e também com Windows 10 de 64 bits .
Em vez de usar o "Wow6432Node"
, que emula um nó mapeando uma árvore de registro em outra fazendo-a aparecer virtualmente, você pode fazer o seguinte:
Decida se você precisa acessar o registro de 64 bits ou de 32 bits e use-o conforme descrito abaixo. Você também pode usar o código que mencionei posteriormente (seção de informações adicionais), que cria uma consulta de união para obter as chaves do registro de ambos os nós em uma consulta - assim, você ainda pode consultá-los usando seu caminho real.
Registro de 64 bits
Para acessar o registro de 64 bits , você pode usar RegistryView.Registry64
o seguinte:
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));
Registro de 32 bits
Se você deseja acessar o registro de 32 bits , use RegistryView.Registry32
o seguinte:
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));
Não se confunda, ambas as versões estão usando Microsoft.Win32.RegistryHive.LocalMachine
como primeiro parâmetro, você faz a distinção entre usar 64 bits ou 32 bits pelo segundo parâmetro ( RegistryView.Registry64
versus RegistryView.Registry32
).
Observe que
Em um Windows de 64 bits, HKEY_LOCAL_MACHINE\Software\Wow6432Node
contém valores usados por aplicativos de 32 bits em execução no sistema de 64 bits. Apenas os verdadeiros aplicativos de 64 bits armazenam seus valores HKEY_LOCAL_MACHINE\Software
diretamente. A subárvore Wow6432Node
é totalmente transparente para aplicativos de 32 bits, os aplicativos de 32 bits ainda veem HKEY_LOCAL_MACHINE\Software
como esperam (é um tipo de redirecionamento). Em versões anteriores do Windows, bem como no Windows 7 de 32 bits (e no Vista de 32 bits), a subárvore Wow6432Node
obviamente não existe.
Devido a um bug no Windows 7 (64 bits), a versão do código-fonte de 32 bits sempre retorna "Microsoft", independentemente da organização que você registrou, enquanto a versão do código-fonte de 64 bits retorna a organização certa.
Voltando ao exemplo que você forneceu, faça da seguinte maneira para acessar o branch de 64 bits:
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");
Informações adicionais - para uso prático:
Eu gostaria de adicionar uma abordagem interessante que Johny Skovdal sugeriu nos comentários, que peguei para desenvolver algumas funções úteis usando sua abordagem: Em algumas situações, você deseja recuperar todas as chaves, independentemente de serem de 32 bits ou 64 bits. Os nomes das instâncias SQL são um exemplo. Você pode usar uma consulta de união nesse caso da seguinte maneira (C # 6 ou superior):
// 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);
}
Agora você pode simplesmente usar as funções acima da seguinte maneira:
Exemplo 1: obter nomes de instância 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}");
}
fornecerá uma lista dos nomes e valores dos valores em sqlRegPath.
Nota: Você pode acessar o valor padrão de uma chave (exibida pela ferramenta de linha de comando REGEDT32.EXE
como (Default)
) se omitir o ValueName
parâmetro nas funções correspondentes acima.
Para obter uma lista de subchaves em uma chave de registro, use a função GetRegKeyNames
ou GetAllRegKeyNames
. Você pode usar essa lista para percorrer outras chaves no registro.
Exemplo 2: Obtenha informações de desinstalação do software instalado
var currentVersionRegPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion";
var uninstallRegPath = $@"{currentVersionRegPath}\Uninstall";
var regKeys = Registry.GetAllRegKeyNames(RegPath: uninstallRegPath);
obterá todas as chaves de desinstalação de 32 e 64 bits.
Observe a manipulação de nulos necessária nas funções porque o servidor SQL pode ser instalado como 32 ou 64 bits (Exemplo 1 acima). As funções estão sobrecarregadas, então você ainda pode passar o parâmetro de 32 bits ou 64 bits se necessário - no entanto, se você omiti-lo, ele tentará ler 64 bits; se falhar (valor nulo), ele lerá os valores de 32 bits.
Há uma especialidade aqui: Como GetAllRegValueNames
geralmente é usado em um contexto de loop (consulte o Exemplo 1 acima), ele retorna um enumerável vazio em vez de null
simplificar os foreach
loops: se não fosse tratado dessa forma, o loop teria que ser prefixado por uma if
verificação de declaração para null
qual seria complicado ter que fazer isso - portanto, isso é tratado uma vez na função.
Por que se preocupar com null? Porque, se você não se importar, terá muito mais dores de cabeça em descobrir por que essa exceção de referência nula foi lançada em seu código - você gastaria muito tempo descobrindo onde e por que isso aconteceu. E se isso aconteceu na produção, você estará muito ocupado estudando arquivos de log ou logs de eventos (espero que tenha implementado o log) ... melhor evitar problemas nulos onde você pode de uma forma defensiva. Os operadores ?.
, ?[
... ]
e ??
podem te ajudar muito (veja o código fornecido acima). Há um bom artigo relacionado discutindo os novos tipos de referência anuláveis em C # , que recomendo ler e também este sobre o operador Elvis.
Dica: você pode usar a edição gratuita do Linqpad para testar todos os exemplos no Windows. Não requer instalação. Não se esqueça de pressionar F4e entrar Microsoft.Win32
na guia de importação de Namespace. No Visual Studio, você precisa using Microsoft.Win32;
na parte superior do código.
Dica: para se familiarizar com os novos operadores de manipulação de nulos , experimente (e depure) o seguinte código no LinqPad:
Exemplo 3: Demonstrando operadores de manipulação de nulos
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>"
}
Experimente com .Net fiddle
Se você estiver interessado, aqui estão alguns exemplos que juntei mostrando o que mais você pode fazer com a ferramenta.