Reading the registry and Wow6432Node key
Asked Answered
W

4

62

I have some code that reads the registry and looks for a value in HKEY_LOCAL_MACHINE\Software\App\ but when running on 64-bit versions of Windows the value is under HKEY_LOCAL_MACHINE\Software\Wow6432Node\App\.

How should I best approach this? Do I need a 64-bit installer or should I rewrite my code to detect both places?

Wily answered 11/1, 2010 at 0:0 Comment(2)
Which program manages the registry keys under HKEY_LOCAL_MACHINE\Software\App? Are you trying to read registry keys created by another program?Englishism
Hi, No it is my app that reads the key, the key is written in the registry by the Visual Studio 2008 installer.Wily
H
54

If you mark you C# program as x86 (and not Any CPU) then it will see HKEY_LOCAL_MACHINE\Software\Wow6432Node\App as HKEY_LOCAL_MACHINE\Software\App\.

A .NET program for Any CPU will run as a 64-bit process if 64-bit .NET is installed. The 32-bit registry is under the Wow6432Node for 64-bit programs.

Holomorphic answered 11/1, 2010 at 5:36 Comment(3)
@Arve: I hate to be the bearer of bad news, but this trick does nothing for older WinXP machines - our company still uses hundreds of these and the Wow6432Node key is not on them.Diadromous
The Wow6432Node key only exists on 64bit machinesPuppy
Or if developers 'by mistake' hard code registry key paths with Wow6432Node in them. On my current machine I have this key as evidence: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Wow6432Node\Lenovo. 32 bit code thinking its 64 bit but wants to write to 32 bit registry. Bad Lenovo :)Canonical
F
91

On an x64 machine, here is an example of how to access the 32-bit view of the registry:

using (var view32 = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,
                                            RegistryView.Registry32))
{
  using (var clsid32 = view32.OpenSubKey(@"Software\Classes\CLSID\", false))
  {
    // actually accessing Wow6432Node 
  }
}

... as compared to...

using (var view64 = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,
                                            RegistryView.Registry64))
{
  using (var clsid64 = view64.OpenSubKey(@"Software\Classes\CLSID\", true))
  {
    ....
  }
}
Fayth answered 12/9, 2013 at 18:56 Comment(2)
Nice example. learn.microsoft.com/en-us/windows/desktop/winprog64/… lists which keys are redirected and which are shared.Isolating
Sweet never even knew about the RegistryView. Worked great!Shetrit
H
54

If you mark you C# program as x86 (and not Any CPU) then it will see HKEY_LOCAL_MACHINE\Software\Wow6432Node\App as HKEY_LOCAL_MACHINE\Software\App\.

A .NET program for Any CPU will run as a 64-bit process if 64-bit .NET is installed. The 32-bit registry is under the Wow6432Node for 64-bit programs.

Holomorphic answered 11/1, 2010 at 5:36 Comment(3)
@Arve: I hate to be the bearer of bad news, but this trick does nothing for older WinXP machines - our company still uses hundreds of these and the Wow6432Node key is not on them.Diadromous
The Wow6432Node key only exists on 64bit machinesPuppy
Or if developers 'by mistake' hard code registry key paths with Wow6432Node in them. On my current machine I have this key as evidence: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Wow6432Node\Lenovo. 32 bit code thinking its 64 bit but wants to write to 32 bit registry. Bad Lenovo :)Canonical
D
7

+1 to Wally's answer, but his solution works for .NET 4.0 and higher.

I've found another solution, which also works for .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

Usage:

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");
Derwin answered 26/8, 2014 at 16:5 Comment(0)
E
5

Here's an all-in-one solution that would cover x32 / x64 systems and capture apps installed on local machine or user account.

    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;
    }
Exegesis answered 8/5, 2015 at 0:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.