简体   繁体   English

如何枚举/列出 Windows XP 中所有已安装的应用程序?

[英]How can I enumerate/list all installed applications in Windows XP?

When I say "installed application", I basically mean any application visible in [Control Panel]->[Add/Remove Programs].当我说“已安装的应用程序”时,我基本上是指在[控制面板]->[添加/删除程序]中可见的任何应用程序。

I would prefer to do it in Python, but C or C++ is also fine.我更喜欢用 Python 来做,但 C 或 C++ 也可以。

If you mean the list of installed applications that is shown in Add\\Remove Programs in the control panel, you can find it in the registry key:如果您指的是控制面板中添加\\删除程序中显示的已安装应用程序列表,您可以在注册表项中找到它:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall

more info about how the registry tree is structured can be found here .可以在此处找到有关如何构建注册表树的更多信息

You need to use the winreg API in python to read the values from the registry.您需要使用 python 中的winreg API从注册表中读取值。

Check out the Win32_Product WMI (Windows Management Instrumentation) class.查看Win32_Product WMI(Windows 管理规范)类。 Here's a tutorial on using WMI in Python.这是有关在 Python 中使用 WMI的教程

Control Panel uses Win32 COM api, which is the official method (see Google Groups, Win32)控制面板使用Win32 COM api,这是官方方法(参见Google Groups, Win32)
Never rely on registry.永远不要依赖注册表。

The Microsoft Script Repository has a script for listing all installed software. Microsoft Script Repository 有一个用于列出所有已安装软件的脚本。

import win32com.client
strComputer = "."
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2")
colItems = objSWbemServices.ExecQuery("Select * from Win32_Product")
for objItem in colItems:
    print "Caption: ", objItem.Caption
    print "Description: ", objItem.Description
    print "Identifying Number: ", objItem.IdentifyingNumber
    print "Install Date: ", objItem.InstallDate
    print "Install Date 2: ", objItem.InstallDate2
    print "Install Location: ", objItem.InstallLocation
    print "Install State: ", objItem.InstallState
    print "Name: ", objItem.Name
    print "Package Cache: ", objItem.PackageCache
    print "SKU Number: ", objItem.SKUNumber
    print "Vendor: ", objItem.Vendor
    print "Version: ", objItem.Version

The best registry-based implementation that I have seen is the one written by Chris Wright (chris128) posted at http://www.vbforums.com/showthread.php?t=598355 .我见过的最好的基于注册表的实现是由 Chris Wright (chris128) 编写的,发布在http://www.vbforums.com/showthread.php?t=598355 It uses multiple registry keys and is a lot more complex than any of the answers currently posted here.它使用多个注册表项,并且比目前在此处发布的任何答案都要复杂得多。 It seems to produce identical results to the Add/Remove Programs app, and like the ARP app it also provides an option to include updates.它似乎与添加/删除程序应用程序产生相同的结果,并且与 ARP 应用程序一样,它还提供了一个包含更新的选项。

Although it's implemented in VB.NET, it should be easy to convert to other .NET languages like C# or IronPython.尽管它是在 VB.NET 中实现的,但它应该很容易转换为其他 .NET 语言,如 C# 或 IronPython。 I imagine that converting to IronPython first should make it fairly easy to port to regular Python if that's what you want, but I only converted it to C# myself and then cleaned up the code a bit.我想如果你想要的话,首先转换为 IronPython 应该可以很容易地移植到常规 Python,但我自己只将它转换为 C#,然后稍微清理了代码。

Only one small bug to point out: GetUserInstallerKeyPrograms() doesn't add the version for user programs to the list, even though it extracts it.只有一个小错误需要指出:GetUserInstallerKeyPrograms() 没有将用户程序的版本添加到列表中,即使它提取了它。 This is easy to fix though.不过这很容易解决。

C#.net code for getting the list of installed software using WMI in xp and win7(wmi is the only way in win7)在xp和win7中使用WMI获取已安装软件列表的C#.net代码(wmi是win7中的唯一方法)

    WqlObjectQuery wqlQuery =
      new WqlObjectQuery("SELECT * FROM Win32_Product");
        ManagementObjectSearcher searcher =
            new ManagementObjectSearcher(wqlQuery);

        foreach (ManagementObject software in searcher.Get()) {
            Console.WriteLine(software["Caption"]);
        }

The OP mentioned XP and also mentioned Python, C or C++ but I found that a lot of information on the net about this topic is either incomplete or incorrect. OP 提到了 XP,也提到了 Python、C 或 C++,但我发现网上关于这个主题的很多信息要么不完整,要么不正确。 An example of the latter is the suggestion to use WMI--specifically, the Win32_Product class;后者的一个例子是建议使用 WMI——特别是Win32_Product类; however, as is noted elsewhere, that method is slow , partly because, believe it or not, each MSI found actually runs its repair.然而,正如其他地方所指出的,这种方法很,部分原因是,不管你信不信,发现的每个 MSI 实际上都在运行它的修复。 I call that solution incorrect because of how painfully slow it is and because of its nasty side-effect.我称该解决方案是不正确的,因为它的速度非常缓慢,而且还有令人讨厌的副作用。 For instance, you have already opted to disable a program's Windows service but calling select * from Win32_Product , as part of ensuring that the MSI repair runs, will apparently re-enable the service.例如,您已经选择禁用程序的 Windows 服务,但是select * from Win32_Product调用select * from Win32_Product ,作为确保 MSI 修复运行的一部分,显然会重新启用该服务。

For what it's worth, below is what I would consider to be the most complete example to date, albeit in C# (I compiled it against Framework 4.6.1 but lower versions may work too.) It lists 32-bit and 64-bit installed programs;就其价值而言,以下是我认为迄今为止最完整的示例,尽管是在 C# 中(我针对 Framework 4.6.1 编译它,但较低版本也可以工作。)它列出了 32 位和 64 位安装程式; it disposes registry keys that it uses and it runs in under a second, at least after caching kicks in. Improvements are welcome.它处理它使用的注册表项,并在一秒钟内运行,至少在缓存启动后。欢迎改进。

One thing it is still missing is some updates.有一件事它仍然缺少一些更新。 For example, when I run it on my Windows 10 system and compare it with Control Panel |例如,当我在我的 Windows 10 系统上运行它并与控制面板进行比较时 | Programs and Features |程序和功能 | Installed Updates, I notice that it does not show Security Update for Adobe Flash Player for some reason.已安装的更新,我注意到由于某种原因它没有显示Security Update for Adobe Flash Player

I don't have any good reason for the anonymous method, it's just how I was thinking at the time--a sort of method-within-a-method solution.我对匿名方法没有任何充分的理由,这正是我当时的想法——一种方法中的方法解决方案。

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Win32;

class Program
{
    static void Main(string[] args)
    {
        var result = InstalledProgram.GetAllInstalledPrograms();

        result.Sort((a, b) => a.DisplayName.CompareTo(b.DisplayName));

        foreach(var program in result)
        {
            if(!program.IsSystemComponent && !program.IsKB) Console.WriteLine(program.Dump());
        }
    }
}

public enum PlatformTypes
{
    x86,
    amd64
}

public class InstalledProgram
{
    [DllImport("advapi32.dll")]
    extern public static int RegQueryInfoKey(
        Microsoft.Win32.SafeHandles.SafeRegistryHandle hkey,
        StringBuilder lpClass,
        ref uint lpcbClass,
        IntPtr lpReserved,
        IntPtr lpcSubKeys,
        IntPtr lpcbMaxSubKeyLen,
        IntPtr lpcbMaxClassLen,
        IntPtr lpcValues,
        IntPtr lpcbMaxValueNameLen,
        IntPtr lpcbMaxValueLen,
        IntPtr lpcbSecurityDescriptor,
        out long lpftLastWriteTime
    );

    public string DisplayName { get; private set; }
    public string UninstallString { get; private set; }
    public string KBNumber { get; private set; }
    public string DisplayIcon { get; private set; }
    public string Version { get; private set; }
    public DateTime InstallDate { get; private set; }
    public PlatformTypes Platform { get; private set; }
    public bool IsSystemComponent { get; private set; }
    public bool IsKB { get { return !string.IsNullOrWhiteSpace(KBNumber); } }

    public static List<InstalledProgram> GetAllInstalledPrograms()
    {
        var result = new List<InstalledProgram>();

        Action<PlatformTypes, RegistryKey, string> getRegKeysForRegPath = (platform, regBase, path) =>
        {
            using(var baseKey = regBase.OpenSubKey(path))
            {
                if(baseKey != null)
                {
                    string[] subKeyNames = baseKey.GetSubKeyNames();
                    foreach(string subkeyName in subKeyNames)
                    {
                        using(var subKey = baseKey.OpenSubKey(subkeyName))
                        {
                            object o;

                            o = subKey.GetValue("DisplayName");
                            string displayName = o != null ? o.ToString() : "";
                            o = subKey.GetValue("UninstallString");
                            string uninstallString = o != null ? o.ToString() : "";
                            o = subKey.GetValue("KBNumber");
                            string kbNumber = o != null ? o.ToString() : "";
                            o = subKey.GetValue("DisplayIcon");
                            string displayIcon = o != null ? o.ToString() : "";
                            o = subKey.GetValue("DisplayVersion");
                            string version = o != null ? o.ToString() : "";
                            o = subKey.GetValue("InstallDate");
                            DateTime installDate = o != null ? parseInstallDate(o.ToString()) : default(DateTime);
                            o = subKey.GetValue("SystemComponent");
                            bool isSystemComponent = o != null ? o.ToString() == "1" : false;

                            // Sometimes, you need to get the KB number another way.
                            if(kbNumber == "")
                            {
                                var match = Regex.Match(displayName, @".*?\((KB\d+?)\).*");
                                if(match.Success) kbNumber = match.Groups[1].ToString();
                            }

                            // Sometimes, the only way you can get install date is from the last write
                            // time on the registry key.
                            if(installDate == default(DateTime))
                            {
                                string keyFull = baseKey + "\\" + subkeyName + "\\DisplayVersion";
                                var sb = new StringBuilder(64);
                                uint sbLen = 65;

                                RegQueryInfoKey(
                                        subKey.Handle
                                        , sb
                                        , ref sbLen
                                        , IntPtr.Zero
                                        , IntPtr.Zero
                                        , IntPtr.Zero
                                        , IntPtr.Zero
                                        , IntPtr.Zero
                                        , IntPtr.Zero
                                        , IntPtr.Zero
                                        , IntPtr.Zero
                                        , out long lastWriteTime);

                                installDate = DateTime.FromFileTime(lastWriteTime);
                            }

                            if(displayName != "" && uninstallString != "")
                            {
                                result.Add(new InstalledProgram
                                {
                                    DisplayName = displayName,
                                    UninstallString = uninstallString,
                                    KBNumber = kbNumber,
                                    DisplayIcon = displayIcon,
                                    Version = version,
                                    InstallDate = installDate,
                                    Platform = platform,
                                    IsSystemComponent = isSystemComponent
                                });
                            }
                        }
                    }
                }
            }
        };

        getRegKeysForRegPath(PlatformTypes.amd64, Registry.LocalMachine, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
        getRegKeysForRegPath(PlatformTypes.amd64, Registry.CurrentUser, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
        if(Environment.Is64BitOperatingSystem)
        {
            getRegKeysForRegPath(PlatformTypes.x86, Registry.LocalMachine, @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
            getRegKeysForRegPath(PlatformTypes.x86, Registry.CurrentUser, @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
        }

        return result;
    }

    public string Dump()
    {
        return Platform + "\t" + DisplayName + "\t" + InstallDate + "\t" + DisplayIcon + "\t" + Version + "\t" + KBNumber + "\t" + UninstallString;
    }

    private static DateTime parseInstallDate(string installDateStr)
    {
        DateTime.TryParseExact(
                installDateStr
                , format: "yyyyMMdd"
                , provider: new System.Globalization.CultureInfo("en-US")
                , style: System.Globalization.DateTimeStyles.None
                , result: out DateTime result);

        return result;
    }

    public override string ToString()
    {
        return DisplayName;
    }
}

[Sigh] and then I saw @PolyTekPatrick's answer. [叹气] 然后我看到了@PolyTekPatrick 的回答。 How did I miss that?我怎么错过了?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM