Получить установленные приложения в системе
Как получить приложения, установленные в системе с помощью кода C#?
15 ответов
Перебор раздела реестра "ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ \Microsoft\Windows\CurrentVersion\Uninstall", по-видимому, дает полный список установленных приложений.
Помимо приведенного ниже примера, вы можете найти версию, аналогичную той, что я сделал здесь.
Это грубый пример, вы, вероятно, захотите сделать что-то, чтобы удалить пустые строки, как во 2-й ссылке.
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))
{
Console.WriteLine(subkey.GetValue("DisplayName"));
}
}
}
В качестве альтернативы вы можете использовать WMI, как уже упоминалось:
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach(ManagementObject mo in mos.Get())
{
Console.WriteLine(mo["Name"]);
}
Но это выполняется немного медленнее, и я слышал, что в нем могут отображаться только программы, установленные в "ALLUSERS", хотя это может быть неверно. Он также игнорирует компоненты и обновления Windows, которые могут быть вам полезны.
Я хотел иметь возможность извлекать список приложений так же, как они появляются в меню "Пуск". Используя реестр, я получал записи, которые не отображаются в меню "Пуск".
Я также хотел найти путь к exe-файлу и извлечь значок, чтобы в итоге создать красивый лаунчер. К сожалению, при использовании метода реестра это является хитом, поскольку, по моим наблюдениям, эта информация не является надежно доступной.
Моя альтернатива основана на оболочке:AppsFolder, к которой вы можете получить доступ, запустив explorer.exe shell:appsFolder
и в котором перечислены все приложения, включая приложения магазина, установленные и доступные в данный момент через меню "Пуск". Проблема в том, что это виртуальная папка, доступ к которой невозможно System.IO.Directory
, Вместо этого вам придется использовать собственные команды shell32. К счастью, Microsoft опубликовала https://www.nuget.org/packages/Microsoft.WindowsAPICodePack-Shell/ на Nuget, которая является оболочкой для вышеупомянутых команд. Достаточно сказать, вот код:
// GUID taken from https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid
var FODLERID_AppsFolder = new Guid("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
ShellObject appsFolder = (ShellObject)KnownFolderHelper.FromKnownFolderId(FODLERID_AppsFolder);
foreach (var app in (IKnownFolder)appsFolder)
{
// The friendly app name
string name = app.Name;
// The ParsingName property is the AppUserModelID
string appUserModelID = app.ParsingName; // or app.Properties.System.AppUserModel.ID
// You can even get the Jumbo icon in one shot
ImageSource icon = app.Thumbnail.ExtraLargeBitmapSource;
}
И это все, что нужно сделать. Вы также можете запустить приложения, используя
System.Diagnostics.Process.Start("explorer.exe", @" shell:appsFolder\" + appModelUserID);
Это работает для обычных приложений Win32 и приложений магазина UWP. Как насчет яблок?
Поскольку вы заинтересованы в перечислении всех установленных приложений, разумно ожидать, что вы, возможно, захотите отслеживать новые приложения или удаленные приложения, что вы можете сделать, используя ShellObjectWatcher
:
ShellObjectWatcher sow = new ShellObjectWatcher(appsFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();
Редактировать: Также может быть интересно узнать, что упомянутый выше AppUserMoedlID является уникальным идентификатором, который Windows использует для группировки окон на панели задач.
Вы можете взглянуть на эту статью. Он использует реестр, чтобы прочитать список установленных приложений.
public void GetInstalledApps()
{
string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(uninstallKey))
{
foreach (string skName in rk.GetSubKeyNames())
{
using (RegistryKey sk = rk.OpenSubKey(skName))
{
try
{
lstInstalled.Items.Add(sk.GetValue("DisplayName"));
}
catch (Exception ex)
{ }
}
}
}
}
Я согласен, что перечисление через раздел реестра - лучший способ.
Обратите внимание, однако, что данный ключ, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
, перечислит все приложения в 32-разрядной установке Windows и 64-разрядные приложения в 64-разрядной установке Windows.
Чтобы также увидеть 32-разрядные приложения, установленные в 64-разрядной версии Windows, вам также необходимо перечислить ключ @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
,
Хотя принятое решение работает, оно не является полным. Безусловно.
Если вы хотите получить все ключи, вам нужно учесть еще 2 вещи:
Приложения x86 и x64 не имеют доступа к одному и тому же реестру. Обычно x86 не может получить доступ к реестру x64. А некоторые приложения регистрируются только в реестре x64.
а также
некоторые приложения фактически устанавливаются в реестр CurrentUser вместо LocalMachine
Имея это в виду, мне удалось получить ВСЕ установленные приложения, используя следующий код, БЕЗ использования WMI
Вот код:
List<string> installs = new List<string>();
List<string> keys = new List<string>() {
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
};
// The RegistryView.Registry64 forces the application to open the registry as x64 even if the application is compiled as x86
FindInstalls(RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64), keys, installs);
FindInstalls(RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64), keys, installs);
installs = installs.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList();
installs.Sort(); // The list of ALL installed applications
private void FindInstalls(RegistryKey regKey, List<string> keys, List<string> installed)
{
foreach (string key in keys)
{
using (RegistryKey rk = regKey.OpenSubKey(key))
{
if (rk == null)
{
continue;
}
foreach (string skName in rk.GetSubKeyNames())
{
using (RegistryKey sk = rk.OpenSubKey(skName))
{
try
{
installed.Add(Convert.ToString(sk.GetValue("DisplayName")));
}
catch (Exception ex)
{ }
}
}
}
}
}
Стоит отметить, что класс WMI Win32_Product представляет продукты в том виде, в котором они установлены установщиком Windows [ http://msdn.microsoft.com/en-us/library/aa394378%28v=vs.85%29.aspx%5D.not каждого приложения использовать установщик Windows
однако "ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ \Microsoft\Windows\CurrentVersion\Uninstall" представляет приложения для 32-разрядных. Для 64-битной системы вам также необходимо пройти "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall", и поскольку не у каждой программы есть 64-битная версия, все установленные приложения представляют собой объединение ключей в обоих местах с "UninstallString". Ценность с ними.
но лучшие варианты остаются теми же. Ключи реестра.traverse - лучший подход, так как у каждого приложения есть запись в реестре [включая записи в установщике Windows]. Однако метод реестра небезопасен, как если бы кто-то удалял соответствующий ключ, тогда вы не узнаете запись приложения. Напротив, изменение HKEY_Classes_ROOT\Installers более сложно, поскольку оно связано с проблемами лицензирования, такими как Microsoft office или другие продукты. для более надежного решения вы всегда можете объединить альтернативу реестра с WMI.
Перебирайте ключи "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" и проверяйте их значения "DisplayName".
Как указывали другие, принятый ответ не возвращает установки как x86, так и x64. Ниже мое решение для этого. Это создает
StringBuilder
, добавляет к нему значения реестра (с форматированием) и записывает результат в текстовый файл:
const string FORMAT = "{0,-100} {1,-20} {2,-30} {3,-8}\n";
private void LogInstalledSoftware()
{
var line = string.Format(FORMAT, "DisplayName", "Version", "Publisher", "InstallDate");
line += string.Format(FORMAT, "-----------", "-------", "---------", "-----------");
var sb = new StringBuilder(line, 100000);
ReadRegistryUninstall(ref sb, RegistryView.Registry32);
sb.Append($"\n[64 bit section]\n\n{line}");
ReadRegistryUninstall(ref sb, RegistryView.Registry64);
File.WriteAllText(@"c:\temp\log.txt", sb.ToString());
}
private static void ReadRegistryUninstall(ref StringBuilder sb, RegistryView view)
{
const string REGISTRY_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
using var subKey = baseKey.OpenSubKey(REGISTRY_KEY);
foreach (string subkey_name in subKey.GetSubKeyNames())
{
using RegistryKey key = subKey.OpenSubKey(subkey_name);
if (!string.IsNullOrEmpty(key.GetValue("DisplayName") as string))
{
var line = string.Format(FORMAT,
key.GetValue("DisplayName"),
key.GetValue("DisplayVersion"),
key.GetValue("Publisher"),
key.GetValue("InstallDate"));
sb.Append(line);
}
key.Close();
}
subKey.Close();
baseKey.Close();
}
string[] registryKeys = new string[] {
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" };
public class InstalledApp
{
public string DisplayName { get; set; }
public string DisplayIcon { get; set; }
public string Version { get; set; }
public string InstallLocation { get; set; }
}
private void AddInstalledAppToResultView(RegistryHive hive, RegistryView view, string registryKey,Dictionary<string,InstalledApp> resultView)
{
using (var key = RegistryKey.OpenBaseKey(hive, view).OpenSubKey(registryKey))
{
foreach (string subKeyName in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subKeyName))
{
var displayName = subkey.GetValue("DisplayName");
var displayIcon = subkey.GetValue("DisplayIcon");
if (displayName == null || displayIcon == null)
continue;
var app = new InstalledApp
{
DisplayName = (string)displayName,
DisplayIcon = (string)displayIcon,
InstallLocation = (string)subkey.GetValue("InstallLocation"),
Version = (string)subkey.GetValue("DisplayVersion")
};
if(!resultView.ContainsKey(app.DisplayName))
{
resultView.Add(app.DisplayName,app);
}
}
}
}
}
void Main()
{
var result = new Dictionary<string,InstalledApp>();
var view = Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32;
AddInstalledAppToResultView(RegistryHive.LocalMachine, view, registryKeys[0],result);
AddInstalledAppToResultView(RegistryHive.CurrentUser, view, registryKeys[0],result);
AddInstalledAppToResultView(RegistryHive.LocalMachine, RegistryView.Registry64, registryKeys[1],result);
Console.WriteLine("==============" + result.Count + "=================");
result.Values.ToList().ForEach(item => Console.WriteLine(item));
}
Объект для списка:
public class InstalledProgram
{
public string DisplayName { get; set; }
public string Version { get; set; }
public string InstalledDate { get; set; }
public string Publisher { get; set; }
public string UnninstallCommand { get; set; }
public string ModifyPath { get; set; }
}
Призыв к созданию списка:
List<InstalledProgram> installedprograms = new List<InstalledProgram>();
string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
if (subkey.GetValue("DisplayName") != null)
{
installedprograms.Add(new InstalledProgram
{
DisplayName = (string)subkey.GetValue("DisplayName"),
Version = (string)subkey.GetValue("DisplayVersion"),
InstalledDate = (string)subkey.GetValue("InstallDate"),
Publisher = (string)subkey.GetValue("Publisher"),
UnninstallCommand = (string)subkey.GetValue("UninstallString"),
ModifyPath = (string)subkey.GetValue("ModifyPath")
});
}
}
}
}
Могу ли я предложить вам взглянуть на WMI ( инструментарий управления Windows). Если вы добавите ссылку на System.Management в свой проект на C#, вы получите доступ к классу ManagementObjectSearcher, который вам, вероятно, будет полезен.
Существуют различные классы WMI для установленных приложений, но если он был установлен с помощью установщика Windows, то класс Win32_Product, вероятно, лучше всего подходит для вас.
ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
Я использовал подход Никса - мне нужно было проверить, установлены ли Remote Tools for Visual Studio или нет, это кажется немного медленным, но в отдельном потоке это хорошо для меня. - вот мой расширенный код:
private bool isRdInstalled() {
ManagementObjectSearcher p = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach (ManagementObject program in p.Get()) {
if (program != null && program.GetPropertyValue("Name") != null && program.GetPropertyValue("Name").ToString().Contains("Microsoft Visual Studio 2012 Remote Debugger")) {
return true;
}
if (program != null && program.GetPropertyValue("Name") != null) {
Trace.WriteLine(program.GetPropertyValue("Name"));
}
}
return false;
}
Используйте API установщика Windows!
Это позволяет составить достоверный перечень всех программ. Реестр ненадежен, но WMI имеет большой вес.
Лучше всего использовать WMI. В частности, класс Win32_Product.
Мое требование - проверить, установлено ли в моей системе определенное программное обеспечение. Это решение работает, как и ожидалось. Это может помочь вам. Я использовал приложение Windows в C# с Visual Studio 2015.
private void Form1_Load(object sender, EventArgs e)
{
object line;
string softwareinstallpath = string.Empty;
string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (var baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
using (var key = baseKey.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (var subKey = key.OpenSubKey(subkey_name))
{
line = subKey.GetValue("DisplayName");
if (line != null && (line.ToString().ToUpper().Contains("SPARK")))
{
softwareinstallpath = subKey.GetValue("InstallLocation").ToString();
listBox1.Items.Add(subKey.GetValue("InstallLocation"));
break;
}
}
}
}
}
if(softwareinstallpath.Equals(string.Empty))
{
MessageBox.Show("The Mirth connect software not installed in this system.")
}
string targetPath = softwareinstallpath + @"\custom-lib\";
string[] files = System.IO.Directory.GetFiles(@"D:\BaseFiles");
// Copy the files and overwrite destination files if they already exist.
foreach (var item in files)
{
string srcfilepath = item;
string fileName = System.IO.Path.GetFileName(item);
System.IO.File.Copy(srcfilepath, targetPath + fileName, true);
}
return;
}