17

我阅读了很多获取程序的信息。没有一种算法能做到我想要的。我需要像在控制面板中一样安装程序

所以我用:

  1. WMIWin32_Product类。它仅显示 msi 安装的程序。
  2. 注册表项。HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall. 同样,控制面板中不显示某些程序,控制面板中显示的某些程序不在此注册表节点中。

那么,这个世界上有没有人知道哪个算法使用控制面板来显示已安装的程序?

UPD1:是的,我使用 64 位,我知道还有另一个节点用于 64 位安装程序“HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall”,但以下代码枚举了两次 HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\ CurrentVersion\Uninstall 部分,奇怪...

var 程序 = 新列表();string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; using (Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key)) { foreach (string subkey_name in key.GetSubKeyNames()) { using (RegistryKey subkey = key.OpenSubKey(subkey_name)) { var name = (string) subkey.GetValue("DisplayName"); if(!string.IsNullOrEmpty(name)) {programs.Add(name); } } } } registry_key = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"; 使用 (Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key)) { foreach (string subkey_name in key. GetSubKeyNames()) { using (RegistryKey subkey = key.OpenSubKey(subkey_name)) { var name = (string)subkey.GetValue("DisplayName"); if (!string.IsNullOrEmpty(name)) {programs.Add(name); } } } } foreach (var program in programs.OrderBy(x => x)) { Console.WriteLine(program); } x)) { Console.WriteLine(程序); } x)) { Console.WriteLine(程序); }
4

4 回答 4

33

Ok gyus,我编写的类可以从注册表中获取已安装的程序,而无需修补程序和更新。它仍然不完全像在控制面板中,但几乎。我希望这对其他人有帮助。

公共静态类 InstalledPrograms
{
    const string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";

public static List<string> GetInstalledPrograms() { var result = new List<string>(); result.AddRange(GetInstalledProgramsFromRegistry(RegistryView.Registry32)); result.AddRange(GetInstalledProgramsFromRegistry(RegistryView.Registry64)); return result; } private static IEnumerable<string> GetInstalledProgramsFromRegistry(RegistryView registryView) { var result = new List<string>(); using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView).OpenSubKey(registry_key)) { foreach (string subkey_name in key.GetSubKeyNames()) { using (RegistryKey subkey = key.OpenSubKey(subkey_name)) { if(IsProgramVisible(subkey)) { result.Add((string)subkey.GetValue("DisplayName")); } } } } return result; } private static bool IsProgramVisible(RegistryKey subkey) { var name = (string)subkey.GetValue("DisplayName"); var releaseType = (string)subkey.GetValue("ReleaseType"); //var unistallString = (string)subkey.GetValue("UninstallString"); var systemComponent = subkey.GetValue("SystemComponent"); var parentName = (string)subkey.GetValue("ParentDisplayName"); return !string.IsNullOrEmpty(name) && string.IsNullOrEmpty(releaseType) && string.IsNullOrEmpty(parentName) && (systemComponent == null); } }

于 2013-03-21T06:12:03.393 回答
4

MelnikovI 的答案对于大多数用途来说已经足够了——我的列表中有 144 项,而程序和功能中有 143 项。 对于审查,他的解决方案是点击这些注册表位置:

  • HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall
  • HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

要获得资格,每个子项必须具有:

  • DisplayName REG_SZ 值

并且不得有:

  • SystemComponent REG_DWORD(非零)
  • ParentKeyName 或 ParentDisplayName REG_SZ 值
  • ReleaseType REG_SZ 值

我发现的一项附加增强功能是针对 Windows Installer 条目,定义为:

  • 键名是标准 GUID 字符串
  • WindowsInstaller REG_DWORD 存在(并且非零)

对于此类条目,您可以采取额外的步骤,即使用 msi.dll 中的 Win32 函数MsiGetProductInfoW 并为键表示的 GUID 请求“VersionString”属性。

如果此函数返回1605: ERROR_UNKNOWN_PRODUCT,则表示该条目未根据 Windows Installer 安装,应从显示中排除。

在实施了这个小调整之后,我的列表现在与程序和功能相同。

于 2015-10-22T05:40:00.310 回答
2

我采用了 MelnikovI 编写的代码(非常有用)并添加了一些东西。首先,它在注册表中搜索四个位置:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

HKCU\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

它还检查是否有任何子键 - 如果没有,它会跳过那个。

最后,它做了一个正则表达式,只允许一组特定的字符 [^a-zA-Z0-9 .()+-]。

我只是从 C# 开始,所以我不知道循环遍历所有四个 reg 位置的方法,所以我有两个循环(一个用于 HKLM,一个用于 HKCU)。

public static class InstalledPrograms
    {
      public static List<string> GetInstalledPrograms()
        {
            var result = new List<string>();
            result.AddRange(GetInstalledProgramsFromRegistry(RegistryView.Registry32));
            result.AddRange(GetInstalledProgramsFromRegistry(RegistryView.Registry64));
            result.Sort();
            return result;
        }
        private static string cleanText(string dirtyText)
        {
            Regex rgx = new Regex("[^a-zA-Z0-9 .()+-]");
            string result = rgx.Replace(dirtyText, "");
            return result;
        }
        private static IEnumerable<string> GetInstalledProgramsFromRegistry(RegistryView registryView)
        {
            var result = new List<string>();
            List<string> uninstall = new List<string>();
            uninstall.Add(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
            uninstall.Add(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
            foreach (string registry_key in uninstall)
            {
               using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView).OpenSubKey(registry_key))
               {
                    foreach (string subkey_name in key.GetSubKeyNames())
                    {
                        using (RegistryKey subkey = key.OpenSubKey(subkey_name))
                        {
                            if (IsProgramVisible(subkey))
                            {
                                result.Add(cleanText(subkey.GetValue("DisplayName").ToString()).ToString());
                            }
                        }
                    }
                }
                using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, registryView).OpenSubKey(registry_key))
                {
                    if (key != null)
                    {
                        foreach (string subkey_name in key.GetSubKeyNames())
                        {
                            using (RegistryKey subkey = key.OpenSubKey(subkey_name))
                            {
                                if (IsProgramVisible(subkey))
                                {
                                    result.Add(cleanText(subkey.GetValue("DisplayName").ToString()).ToString());
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }

如果有人感兴趣,我将结果与我一直在使用的 PowerShell 进行了比较,它们是相同的。

##Get list of Add/Remove programs
if (!([Diagnostics.Process]::GetCurrentProcess().Path -match '\\syswow64\\'))
{
$uninstallPath = "\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
$uninstallWow6432Path = "\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"
@(
if (Test-Path "HKLM:$uninstallWow6432Path" ) { Get-ChildItem "HKLM:$uninstallWow6432Path"}
if (Test-Path "HKLM:$uninstallPath" ) { Get-ChildItem "HKLM:$uninstallPath" }
if (Test-Path "HKCU:$uninstallWow6432Path") { Get-ChildItem "HKCU:$uninstallWow6432Path"}
if (Test-Path "HKCU:$uninstallPath" ) { Get-ChildItem "HKCU:$uninstallPath" }
) |
ForEach-Object { Get-ItemProperty $_.PSPath } |
Where-Object {
$_.DisplayName -and !$_.SystemComponent -and !$_.ReleaseType -and !$_.ParentKeyName -and ($_.UninstallString -or $_.NoRemove)
} |
Sort-Object DisplayName |
Select-Object DisplayName
}
else
{
"You are running 32-bit Powershell on 64-bit system. Please run 64-bit Powershell instead." | Write-Host -ForegroundColor Red
}
于 2015-09-14T21:48:18.477 回答
0

此处在其他几个答案中讨论的 SystemComponent 注册表项通常是 REG_DWORD,可能值为 0 或 1。但是,我见过几个实例(例如 Microsoft Visio 2010 和 Microsoft Project 2010),其中 SystemComponent 是没有数据的 REG_SZ . 因此,任何将 SystemComponent 转换为 int 的解决方案都可能在这些情况下引发异常。

于 2019-04-18T16:36:12.157 回答