How can I enumerate/list all installed application

2019-01-13 20:11发布

问题:

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.

回答1:

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.



回答2:

Check out the Win32_Product WMI (Windows Management Instrumentation) class. Here's a tutorial on using WMI in Python.



回答3:

Control Panel uses Win32 COM api, which is the official method (see Google Groups, Win32)
Never rely on registry.



回答4:

The Microsoft Script Repository has a script for listing all installed software.

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


回答5:

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. 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.

Although it's implemented in VB.NET, it should be easy to convert to other .NET languages like C# or 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.

Only one small bug to point out: GetUserInstallerKeyPrograms() doesn't add the version for user programs to the list, even though it extracts it. This is easy to fix though.



回答6:

C#.net code for getting the list of installed software using WMI in xp and win7(wmi is the only way in win7)

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

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


回答7:

I know this question is old, 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. An example of the latter is the suggestion to use WMI--specifically, the Win32_Product class; however, as is noted elsewhere, that method is slow, partly because, believe it or not, each MSI found actually runs its repair. 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.

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; it disposes registry keys that it uses and it runs in under a second, at least after caching kicks in. If you can offer improvements, please suggest them instead of just downvoting, and I will update the code.

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 | Programs and Features | Installed Updates, I notice that it does not show Security Update for Adobe Flash Player for some reason.

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. How did I miss that? LOL