Stay Hungry.Stay Foolish.
32位C#应用程序在64位操作系统访问64位注册表

需求

用c#读取windows系统上所有安装的软件

问题原因

为了保证程序的最大兼容性,选择了编译成32位应用程序,在64位操作系统上,是有两个注册表的,一个32位的,一个64位的,所以32位程序访问注册表的key时,操作系统会自动转向到32位的注册表上,导致我们无法获取到64位注册表上的软件信息

解决方案

用win32 API设置注册表不自动转向来读取

代码实现

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;

using System.Runtime.InteropServices;
using System.Text;

namespace Tools
{
    class SystemSoft
    {
        static UIntPtr HKEY_CLASSES_ROOT = (UIntPtr)0x80000000;
        static UIntPtr HKEY_CURRENT_USER = (UIntPtr)0x80000001;
        static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
        static UIntPtr HKEY_USERS = (UIntPtr)0x80000003;
        static UIntPtr HKEY_CURRENT_CONFIG = (UIntPtr)0x80000005;
        static int ERROR_NO_MORE_ITEMS = 259;
        static long KEY_NOT_FOUND = 2;
        [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
        // 开启64位(文件系统)的操作转向
        [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);

        // 获取操作Key值句柄
        [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions,
        int samDesired, out IntPtr phkResult);
        //关闭注册表转向(禁用特定项的注册表反射)
        [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern long RegDisableReflectionKey(IntPtr hKey);
        //使能注册表转向(开启特定项的注册表反射)
        [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern long RegEnableReflectionKey(IntPtr hKey);
        //获取Key值(即:Key值句柄所标志的Key对象的值)
        [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, int lpReserved,
         out uint lpType, StringBuilder lpData,
         ref uint lpcbData);

        [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "RegEnumKeyEx")]
        private static extern long RegEnumKeyEx(IntPtr hKey, uint index, StringBuilder lpName, ref uint lpcbName, IntPtr reserved,
            IntPtr lpClass, IntPtr lpcbClass, out long lpftLastWriteTime);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern int RegCloseKey(IntPtr hKey);

        public static string AddressWithIs32or64()
        {
            try
            {
                ConnectionOptions oConn = new ConnectionOptions();
                System.Management.ManagementScope oMs = new System.Management.ManagementScope("\\\\localhost", oConn);
                System.Management.ObjectQuery oQuery = new System.Management.ObjectQuery("select AddressWidth from Win32_Processor");
                ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oMs, oQuery);
                ManagementObjectCollection oReturnCollection = oSearcher.Get();
                string addressWidth = null;

                foreach (ManagementObject oReturn in oReturnCollection)
                {
                    addressWidth = oReturn["AddressWidth"].ToString();
                }
                return addressWidth;
            }
            catch (Exception ex)
            {
                return "32";
            }

        }

        private static UIntPtr TransferKeyName(string keyName)
        {
            switch (keyName)
            {
                case "HKEY_CLASSES_ROOT":
                    return HKEY_CLASSES_ROOT;
                case "HKEY_CURRENT_USER":
                    return HKEY_CURRENT_USER;
                case "HKEY_LOCAL_MACHINE":
                    return HKEY_LOCAL_MACHINE;
                case "HKEY_USERS":
                    return HKEY_USERS;
                case "HKEY_CURRENT_CONFIG":
                    return HKEY_CURRENT_CONFIG;
            }
            return HKEY_CLASSES_ROOT;
        }

        public static void Get32BitRegistrySubKey(Dictionary<string, AppItem> dict, string parentKeyName, string subKeyName)
        {
            int KEY_WOW64_32KEY = (0x0200);
            GetRegistrySubKey(dict, parentKeyName, subKeyName, KEY_WOW64_32KEY);
        }
        public static void Get64BitRegistrySubKey(Dictionary<string, AppItem> dict, string parentKeyName, string subKeyName)
        {
            int KEY_WOW64_64KEY = (0x0100);
            GetRegistrySubKey(dict, parentKeyName, subKeyName, KEY_WOW64_64KEY);
        }

        public static void GetRegistrySubKey(Dictionary<string, AppItem> dict, string parentKeyName, string subKeyName, int KEY_WOW64_KEY)
        {
            int KEY_QUERY_VALUE = (0x0001);
            int KEY_WOW64_64KEY = KEY_WOW64_KEY;
            int KEY_ENUMERATE_SUB_KEYS = (0x0008);
            int KEY_ALL_WOW64 = (KEY_QUERY_VALUE | KEY_WOW64_64KEY | KEY_ENUMERATE_SUB_KEYS);
            try
            {
                //将Windows注册表主键名转化成为不带正负号的整形句柄(与平台是32或者64位有关)
                UIntPtr hKey = TransferKeyName(parentKeyName);

                //声明将要获取Key值的句柄
                IntPtr pHKey = IntPtr.Zero;

                //记录读取到的Key值
                StringBuilder result = new StringBuilder();

                //关闭文件系统转向
                IntPtr oldWOW64State = new IntPtr();
                if (Wow64DisableWow64FsRedirection(ref oldWOW64State))
                {
                    //获得操作Key值的句柄
                    uint ret = RegOpenKeyEx(hKey, subKeyName, 0, KEY_ALL_WOW64, out pHKey);
                    if (ret != KEY_NOT_FOUND)
                    {

                        //关闭注册表转向(禁止特定项的注册表反射)
                        RegDisableReflectionKey(pHKey);

                        uint index = 0;
                        StringBuilder sb = new StringBuilder("".PadLeft(1024));
                        uint MAX_REG_KEY_SIZE = 1024;
                        long writetime = 1024;
                        long re = RegEnumKeyEx(pHKey, index, sb, ref MAX_REG_KEY_SIZE, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, out writetime);
                        if (re != KEY_NOT_FOUND) //键不存在
                        {
                            while (re != ERROR_NO_MORE_ITEMS)
                            {
                                string subKey = subKeyName + "\\" + sb.ToString();
                                AppItem appitem = GetRegistryKey(parentKeyName, subKey, KEY_WOW64_KEY);
                                if (appitem != null)
                                {
                                    string key = sb.ToString();
                                    appitem.identifier = key;
                                    if (!dict.ContainsKey(key))
                                    {
                                        dict.Add(sb.ToString(), appitem);
                                    }
                                }
                                sb = new StringBuilder("".PadLeft(1024));
                                MAX_REG_KEY_SIZE = 1024;
                                index = index + 1;
                                re = RegEnumKeyEx(pHKey, index, sb, ref MAX_REG_KEY_SIZE, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, out writetime);
                            }
                        }
                        //打开注册表转向(开启特定项的注册表反射)
                        RegEnableReflectionKey(pHKey);
                    }

                    //关闭注册句柄
                    RegCloseKey(pHKey);
                }

                //打开文件系统转向
                Wow64RevertWow64FsRedirection(oldWOW64State);
                return;
            }
            catch (Exception ex)
            {
                return;
            }
        }
        public static AppItem GetRegistryKey(string parentKeyName, string subKeyName, int KEY_WOW64_KEY)
        {
            int KEY_QUERY_VALUE = (0x0001);
            int KEY_WOW64_64KEY = KEY_WOW64_KEY;
            int KEY_ENUMERATE_SUB_KEYS = (0x0008);
            int KEY_ALL_WOW64 = (KEY_QUERY_VALUE | KEY_WOW64_64KEY | KEY_ENUMERATE_SUB_KEYS);
            AppItem appitem = null;
            try
            {
                //将Windows注册表主键名转化成为不带正负号的整形句柄(与平台是32或者64位有关)
                UIntPtr hKey = TransferKeyName(parentKeyName);
                //声明将要获取Key值的句柄
                IntPtr pHKey = IntPtr.Zero;
                //关闭文件系统转向
                IntPtr oldWOW64State = new IntPtr();
                if (Wow64DisableWow64FsRedirection(ref oldWOW64State))
                {
                    //获得操作Key值的句柄
                    uint re = RegOpenKeyEx(hKey, subKeyName, 0, KEY_ALL_WOW64, out pHKey);
                    if (re != KEY_NOT_FOUND)
                    {

                        //关闭注册表转向(禁止特定项的注册表反射)
                        RegDisableReflectionKey(pHKey);

                        //获取访问的Key值
                        //记录读取到的Key值
                        uint lpType = 0;
                        uint resultSize = 1024;
                        StringBuilder sys = new StringBuilder("".PadLeft(1024));
                        int ret = RegQueryValueEx(pHKey, "SystemComponent", 0, out lpType, sys, ref resultSize);
                        if (ret == KEY_NOT_FOUND) //键不存在,说明非系统软件
                        {
                            StringBuilder name = new StringBuilder("".PadLeft(1024));
                            ret = RegQueryValueEx(pHKey, "DisplayName", 0, out lpType, name, ref resultSize);
                            if (name.ToString().Trim() != "")
                            {
                                StringBuilder publisher = new StringBuilder("".PadLeft(1024));
                                ret = RegQueryValueEx(pHKey, "Publisher", 0, out lpType, publisher, ref resultSize);
                                StringBuilder version = new StringBuilder("".PadLeft(1024));
                                ret = RegQueryValueEx(pHKey, "DisplayVersion", 0, out lpType, version, ref resultSize);
                                StringBuilder installDate = new StringBuilder("".PadLeft(1024));
                                ret = RegQueryValueEx(pHKey, "InstallDate", 0, out lpType, installDate, ref resultSize);
                                appitem = new AppItem();
                                appitem.publisher = publisher.ToString();
                                appitem.version = version.ToString();
                                appitem.name = name.ToString();
                                string installTime = installDate.ToString().Trim();
                                appitem.installTime = TimeFormat(installTime);
                            }
                        }
                        //打开注册表转向(开启特定项的注册表反射)
                        RegEnableReflectionKey(pHKey);
                        //关闭注册句柄
                    }
                    RegCloseKey(pHKey);
                }

                //打开文件系统转向
                Wow64RevertWow64FsRedirection(oldWOW64State);

                //返回Key值
            }
            catch (Exception ex)
            {
            }
            return appitem;
        }
        public static string TimeFormat(string installTime)
        {
            string time = "";
            if (installTime == "")
            {
                return time;
            }
            try
            {
                time = installTime.Substring(0, 4) + "-" + installTime.Substring(4, 2) + "-" + installTime.Substring(6, 2);
            }
            catch (Exception e)
            {
                time = "";
            }
            return time;
        }
        public static List<AppItem> GetWindowsSoft()
        {
            Dictionary<string, AppItem> dict = new Dictionary<string, AppItem>();
            string sIs64or32System = AddressWithIs32or64();
            if (sIs64or32System.Equals("32"))
            {
                Get32BitWindowsSoft(dict);
            }
            else
            {
                Get32BitRegistrySubKey(dict, "HKEY_LOCAL_MACHINE", @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
                Get32BitRegistrySubKey(dict, "HKEY_CURRENT_USER", @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
                Get64BitRegistrySubKey(dict, "HKEY_LOCAL_MACHINE", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
                Get64BitRegistrySubKey(dict, "HKEY_CURRENT_USER", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
            }
            //Get32BitWindowsSoft(dict);
            List<AppItem> list = new List<AppItem>();
           
            foreach (AppItem item in dict.Values)
            {
                list.Add(item);
            }


            return list;
        }

        public static Dictionary<string, AppItem> Get32BitWindowsSoft(Dictionary<string, AppItem> dict)
        {
            string key = string.Empty;
            RegistryKey localMachine;
            RegistryKey Uninstall;
            IntPtr ptr = new IntPtr();
            IntPtr ptr2 = new IntPtr();

            key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
            localMachine = Registry.LocalMachine;
            Uninstall = localMachine.OpenSubKey(key, false);

            GetInstallSofts(Uninstall,dict);
            Uninstall.Close();
            
            localMachine = Registry.CurrentUser;
            Uninstall = localMachine.OpenSubKey(key, false);

            GetInstallSofts(Uninstall,dict);
            Uninstall.Close();

            return dict;
        }

        private static void GetInstallSofts(RegistryKey Uninstall, Dictionary<string, AppItem> dict)
        {
            foreach (string subkey in Uninstall.GetSubKeyNames())
            {
                try
                {
                    if (subkey == null)
                    {
                        continue;
                    }
                    else
                    {
                        RegistryKey currentKey = Uninstall.OpenSubKey(subkey);

                        AppItem appitem = new AppItem();
                        string name = (string)currentKey.GetValue("DisplayName");
                        string version = (string)currentKey.GetValue("DisplayVersion");
                        string publisher = (string)currentKey.GetValue("publisher");
                        string installTime = (string)currentKey.GetValue("InstallDate");
                        object sys = currentKey.GetValue("SystemComponent");
                        currentKey.Close();
                        if (sys == null)
                        {
                            if (dict.ContainsKey(subkey))
                            {
                                continue;
                            }
                            if (name == "" || name == null)
                            {
                                continue;
                            }
                            appitem.name = name;
                            appitem.version = version;
                            appitem.publisher = publisher;
                            appitem.installTime = TimeFormat(installTime);
                            appitem.identifier = subkey;
                            dict.Add(subkey, appitem);
                        }

                    }
                }
                catch (Exception ex)
                {
                }
            }

            return;
        }
    }
}
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证
评论

暂无评论~~