读取注册表和 Wow6432Node 键

Posted

技术标签:

【中文标题】读取注册表和 Wow6432Node 键【英文标题】:Reading the registry and Wow6432Node key 【发布时间】:2011-01-03 14:17:36 【问题描述】:

我有一些代码可以读取注册表并在 HKEY_LOCAL_MACHINE\Software\App\ 中查找值,但在 64 位版本的 Windows 上运行时,该值低于 HKEY_LOCAL_MACHINE\Software\Wow6432Node\App\

我应该如何最好地解决这个问题?我需要 64 位安装程序还是应该重写我的代码来检测这两个位置?

【问题讨论】:

哪个程序管理 HKEY_LOCAL_MACHINE\Software\App 下的注册表项?您是否正在尝试读取由其他程序创建的注册表项? 嗨,不,是我的应用程序读取了密钥,密钥是由 Visual Studio 2008 安装程序写入注册表的。 【参考方案1】:

如果您将 C# 程序标记为 x86(而不是任何 CPU),那么它会将 HKEY_LOCAL_MACHINE\Software\Wow6432Node\App 视为 HKEY_LOCAL_MACHINE\Software\App\

如果安装了 64 位 .NET,适用于任何 CPU 的 .NET 程序将作为 64 位进程运行。对于 64 位程序,32 位注册表位于 Wow6432Node 下。

【讨论】:

@Arve:我不想成为坏消息的承担者,但是这个技巧对旧的 WinXP 机器没有任何作用——我们公司仍然使用数百台这样的机器,而且 Wow6432Node 密钥不在它们上面。 Wow6432Node 密钥只存在于 64 位机器上 或者如果开发人员“错误地”硬编码注册表项路径,其中包含 Wow6432Node。在我当前的机器上,我有这个密钥作为证据:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Wow6432Node\Lenovo。 32 位代码认为它的 64 位但想要写入 32 位注册表。坏联想:)【参考方案2】:

在 x64 机器上,下面是一个如何访问注册表 32 位视图的示例:

using (var view32 = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,
                                            RegistryView.Registry32))

  using (var clsid32 = view32.OpenSubKey(@"Software\Classes\CLSID\", false))
  
    // actually accessing Wow6432Node 
  

...与...相比...

using (var view64 = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,
                                            RegistryView.Registry64))

  using (var clsid64 = view64.OpenSubKey(@"Software\Classes\CLSID\", true))
  
    ....
  

【讨论】:

很好的例子。 docs.microsoft.com/en-us/windows/desktop/winprog64/… 列出了哪些键被重定向和哪些是共享的。 Sweet 甚至都不知道 RegistryView。效果很好!【参考方案3】:

+1 对 Wally 的回答,但他的解决方案适用于 .NET 4.0 及更高版本。

我找到了另一个解决方案,它也适用于 .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

用法:

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

【讨论】:

【参考方案4】:

这是一个涵盖 x32 / x64 系统并捕获安装在本地计算机或用户帐户上的应用的一体化解决方案。

    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;
    

【讨论】:

以上是关于读取注册表和 Wow6432Node 键的主要内容,如果未能解决你的问题,请参考以下文章

Wow6432Node(32位程序的注册表内容都在这个节点下,也可直接使用%systemroot%syswow64 egedit进行编辑)

无法删除wow6432node,vmware,inc

注册表项 EditionID 在 WOW6432Node 下的值错误 - 有意还是错误?如何绕过?

手贱删了Wow6432node注册表,有没有补救方法

注册表里的 wow6432 node 是干啥用的?

误删wow6432node进不了系统