Я знаю, что этот вопрос старый, ОП упоминал 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. Как я это пропустил? LOL