Когда я говорю «установленное приложение», я в основном имею в виду любое приложение, видимое в [Панель управления] -> [Установка и удаление программ].
Я бы предпочел сделать это на Python, но C или C ++ тоже подойдут.
Когда я говорю «установленное приложение», я в основном имею в виду любое приложение, видимое в [Панель управления] -> [Установка и удаление программ].
Я бы предпочел сделать это на Python, но C или C ++ тоже подойдут.
Если вы имеете в виду список установленных приложений, который отображается в разделе «Установка и удаление программ» панели управления, вы можете найти его в разделе реестра:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
дополнительную информацию о структуре дерева реестра можно найти здесь.
Для чтения значений из реестра необходимо использовать winreg API в Python.
Ознакомьтесь с Win32_Product WMI (инструментарий управления Windows) класс. Вот руководство по использованию WMI в Python.
Панель управления использует Win32 COM api, который является официальным методом (см. Группы Google, Win32)
Никогда не полагайтесь на реестр.
В репозитории сценариев Microsoft есть сценарий для вывода списка всего установленного программного обеспечения.
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
Лучшая реализация на основе реестра, которую я видел, - это написанная Крисом Райтом (chris128), размещенная по адресу http://www.vbforums.com/showthread.php?t=598355. Он использует несколько ключей реестра и намного сложнее, чем любой из ответов, опубликованных в настоящее время здесь. Кажется, что оно дает те же результаты, что и приложение «Установка и удаление программ», и, как и приложение ARP, оно также предоставляет возможность включать обновления.
Хотя он реализован в VB.NET, его должно быть легко преобразовать в другие языки .NET, такие как C # или IronPython. Я полагаю, что преобразование в IronPython в первую очередь должно упростить перенос на обычный Python, если вы этого хотите, но я только сам преобразовал его на C #, а затем немного очистил код.
Следует отметить только одну небольшую ошибку: GetUserInstallerKeyPrograms () не добавляет версию для пользовательских программ в список, хотя и извлекает ее. Однако это легко исправить.
Код C # .net для получения списка установленного программного обеспечения с использованием WMI в xp и win7 (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"]);
}
OP упомянул XP, а также упомянул Python, C или C ++, но я обнаружил, что много информации в сети по этой теме либо неполное, либо неверное. Примером последнего является предложение использовать WMI, в частности класс Win32_Product
; однако, как отмечается в другом месте, этот метод медленный отчасти потому, что, хотите верьте, хотите нет, каждый найденный MSI фактически выполняет свое восстановление. Я называю это решение неправильным из-за того, насколько оно мучительно медленным, и из-за его неприятных побочных эффектов. Например, вы уже выбрали отключение службы Windows для программы, но вызов select * from Win32_Product
, как часть обеспечения запуска восстановления MSI, по-видимому, снова включит службу.
Что бы это ни стоило, ниже приведен наиболее полный пример на сегодняшний день, хотя и на C # (я скомпилировал его для Framework 4.6.1, но более низкие версии тоже могут работать). В нем перечислены 32-разрядные и 64-разрядные установленные версии. программы; он располагает ключами реестра, которые он использует, и запускается менее чем за секунду, по крайней мере, после того, как сработает кеширование. Улучшения приветствуются.
Единственное, чего ему не хватает, так это некоторых обновлений. Например, когда я запускаю его в своей системе Windows 10 и сравниваю с панелью управления | Программы и компоненты | Установил обновления, замечаю, что Security Update for Adobe Flash Player
почему-то не показывает.
У меня нет веских причин для использования анонимного метода, это просто то, как я думал в то время - своего рода решение «метод внутри метода».
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;
}
}
[Вздох], а затем я увидел ответ @PolyTekPatrick. Как я это пропустил?