example - remarks c#
Leyendo el registro y la clave Wow6432Node (4)
Tengo un código que lee el registro y busca un valor en HKEY_LOCAL_MACHINE/Software/App/
pero cuando se ejecuta en versiones de Windows de 64 bits, el valor está bajo HKEY_LOCAL_MACHINE/Software/Wow6432Node/App/
.
¿Cómo debo abordar mejor esto? ¿Necesito un instalador de 64 bits o debo reescribir mi código para detectar ambos lugares?
+1 a la respuesta de Wally, pero su solución funciona para .NET 4.0 y superior.
He encontrado otra solución, que también funciona para .NET 2.0 here
#region RegHelper
enum RegSAM
{
QueryValue = 0x0001,
SetValue = 0x0002,
CreateSubKey = 0x0004,
EnumerateSubKeys = 0x0008,
Notify = 0x0010,
CreateLink = 0x0020,
WOW64_32Key = 0x0200,
WOW64_64Key = 0x0100,
WOW64_Res = 0x0300,
Read = 0x00020019,
Write = 0x00020006,
Execute = 0x00020019,
AllAccess = 0x000f003f
}
static class RegHive
{
public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
}
static class RegistryWOW6432
{
[DllImport("Advapi32.dll")]
static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out int phkResult);
[DllImport("Advapi32.dll")]
static extern uint RegCloseKey(int hKey);
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
public static extern int RegQueryValueEx(int hKey, string lpValueName, int lpReserved, ref uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData);
static public string GetRegKey64(UIntPtr inHive, String inKeyName, string inPropertyName)
{
return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
}
static public string GetRegKey32(UIntPtr inHive, String inKeyName, string inPropertyName)
{
return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
}
static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, string inPropertyName)
{
//UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
int hkey = 0;
try
{
uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
if (0 != lResult) return null;
uint lpType = 0;
uint lpcbData = 1024;
StringBuilder AgeBuffer = new StringBuilder(1024);
RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
string Age = AgeBuffer.ToString();
return Age;
}
finally
{
if (0 != hkey) RegCloseKey(hkey);
}
}
}
#endregion
Uso:
string value64 = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE/Microsoft/Windows NT/CurrentVersion", "RegisteredOrganization");
string value32 = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE/Microsoft/Windows NT/CurrentVersion", "RegisteredOrganization");
Aquí hay una solución todo en uno que cubriría los sistemas x32 / x64 y capturaría las aplicaciones instaladas en la máquina local o la cuenta de usuario.
public class InstalledProgramInfo
{
public string name;
public string path;
}
public static InstalledProgramInfo FindInstalledApp(string findname, bool dump = false)
{
if (String.IsNullOrEmpty(findname)) return null;
string uninstallKey = @"SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall";
RegistryHive[] keys = new RegistryHive[] { RegistryHive.CurrentUser, RegistryHive.LocalMachine };
RegistryView[] views = new RegistryView[] { RegistryView.Registry32, RegistryView.Registry64 };
foreach (var hive in keys)
{
foreach (var view in views)
{
RegistryKey rk = null,
basekey = null;
try
{
basekey = RegistryKey.OpenBaseKey(hive, view);
rk = basekey.OpenSubKey(uninstallKey);
}
catch (Exception ex) { continue; }
if (basekey == null || rk == null)
continue;
if (rk == null)
{
if (dump) Console.WriteLine("ERROR: failed to open subkey ''{0}''", uninstallKey);
return null;
}
if (dump) Console.WriteLine("Reading registry at {0}", rk.ToString());
foreach (string skName in rk.GetSubKeyNames())
{
try
{
RegistryKey sk = rk.OpenSubKey(skName);
if (sk == null) continue;
object skname = sk.GetValue("DisplayName");
object skpath = sk.GetValue("InstallLocation");
if (skpath == null)
{
skpath = sk.GetValue("UninstallString");
if (skpath == null) continue;
FileInfo fi = new FileInfo(skpath.ToString());
skpath = fi.Directory.FullName;
}
if (skname == null || skpath == null) continue;
string thisname = skname.ToString();
string thispath = skpath.ToString();
if (dump) Console.WriteLine("{0}: {1}", thisname, thispath);
if (!thisname.Equals(findname, StringComparison.CurrentCultureIgnoreCase))
continue;
InstalledProgramInfo inf = new InstalledProgramInfo();
inf.name = thisname;
inf.path = thispath;
return inf;
}
catch (Exception ex)
{
// todo
}
}
} // view
} // hive
return null;
}
En una máquina x64, aquí hay un ejemplo de cómo acceder a la vista de 32 bits del registro:
using (var view32 = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,
RegistryView.Registry32))
{
using (var clsid32 = view32.OpenSubKey(@"Software/Classes/CLSID/", false))
{
// actually accessing Wow6432Node
}
}
... en comparación con...
using (var view64 = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,
RegistryView.Registry64))
{
using (var clsid64 = view64.OpenSubKey(@"Software/Classes/CLSID/", true))
{
....
}
}
Si marca su programa C # como x86 (y no cualquier CPU), verá HKEY_LOCAL_MACHINE/Software/Wow6432Node/App
como HKEY_LOCAL_MACHINE/Software/App/
.
Un programa .NET para cualquier CPU se ejecutará como un proceso de 64 bits si se instala .NET de 64 bits. El registro de 32 bits se encuentra bajo el Wow6432Node
para programas de 64 bits.