Як отримати програми, встановлені в системі, за допомогою коду c #?
Відповіді:
Ітерація через ключ реєстру "ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ \ Microsoft \ Windows \ CurrentVersion \ Uninstall", здається, дає повний перелік встановлених програм.
Окрім прикладу нижче, ви можете знайти подібну версію до того, що я зробив тут .
Це приблизний приклад, ви, ймовірно, захочете щось зробити, щоб видалити порожні рядки, як у другому наданому посиланні.
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, які можуть вам стати в нагоді.
Ви можете поглянути на цю статтю . Він використовує реєстр для читання списку встановлених програм.
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"
.
regedit
це так здається. Однак у 32-розрядної програмі (у 64-розрядної Windows) обидва списки ідентичні списку WOW6432Node
з regedit
.
Я хотів мати можливість витягти список програм так само, як вони з’являються в меню «Пуск». Використовуючи реєстр, я отримував записи, які не відображаються в меню «Пуск».
Я також хотів знайти шлях до exe та витягнути піктограму, щоб врешті-решт зробити симпатичний запуск. На жаль, з використанням методу реєстру це є певним випадком, оскільки я зауважую, що ця інформація недоступна.
Моя альтернатива заснована на оболонці: AppsFolder, до якої ви можете отримати доступ, запустивши її, explorer.exe shell:appsFolder
і в якій перелічені всі програми, включаючи додатки магазину, встановлені на даний момент і доступні через меню «Пуск». Проблема в тому, що це віртуальна папка, до якої неможливо отримати доступ System.IO.Directory
. Натомість вам довелося б використовувати власні команди shell32. На щастя, Microsoft опублікувала Microsoft.WindowsAPICodePack-Shell на Nuget, який є обгорткою для вищезазначених команд. Досить сказано, ось код:
// GUID taken from https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid
var FOLDERID_AppsFolder = new Guid("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
ShellObject appsFolder = (ShellObject)KnownFolderHelper.FromKnownFolderId(FOLDERID_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 використовує для групування вікон на панелі завдань .
AllEvents
таких , як ItemCreated
або ItemRenamed
що я намагався використовувати , щоб стежити за додатками , як вони були встановлені або видалені. Аргументи подій цих подій містять Path
властивість, але ця властивість завжди має значення null, принаймні в моїх тестах. Натомість я просто зберігаю список програм, які синхронізую щоразу, коли елемент піднімається шляхом перебору програм у папці. Не ідеально, але виконує роботу.
Варто зазначити, що клас WMI Win32_Product представляє продукти, які вони встановлюються установчиком Windows . не кожен додаток використовує інсталятор Windows
однак "ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ \ Microsoft \ Windows \ CurrentVersion \ Uninstall" представляє програми для 32-розрядної версії. Для 64-розрядної версії вам також потрібно пройти "HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall", а оскільки не кожне програмне забезпечення має 64-розрядну версію, загальна кількість встановлених програм є об'єднанням ключів в обох місцях, які мають "UninstallString" Цінність з ними.
але найкращі варіанти залишаються тими самими .traverse ключі реєстру є кращим підходом, оскільки кожна програма має запис у реєстрі [включаючи ті, що встановлені в Windows Installer]. однак метод реєстру є небезпечним, ніби хтось видаляє відповідний ключ, тоді ви не знатимете Навпаки, зміна HKEY_Classes_ROOT \ Installers є більш складною, оскільки вона пов’язана з проблемами ліцензування, такими як Microsoft Office або інші продукти. для більш надійного рішення ви завжди можете поєднати альтернативу реєстру з WMI.
Поки прийняте рішення працює, воно не є повним. На багато.
Якщо ви хочете отримати всі ключі, вам слід взяти до уваги ще 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)
{ }
}
}
}
}
}
Переглядайте клавіші "HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" та перевіряйте їх значення "DisplayName".
Використовуйте API інсталятора Windows!
Це дозволяє зробити надійний перелік усіх програм. Реєстр не є надійним, але WMI є надважкою.
Об'єкт для списку:
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")
});
}
}
}
}
Як зазначали інші, прийнята відповідь не повертає встановлення x86 та x64. Нижче наведено моє рішення для цього. Він створює a 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();
}
Найкраще використовувати WMI . Зокрема клас Win32_Product .
Я можу запропонувати вам поглянути на WMI ( Інструментарій управління Windows ). Якщо ви додасте посилання System.Management до свого проекту C #, ви отримаєте доступ до класу `ManagementObjectSearcher ', який вам, мабуть, стане в нагоді.
Існують різні класи WMI для встановлених програм , але якщо він був встановлений за допомогою інсталятора Windows, то клас Win32_Product, мабуть, найкраще вам підходить.
ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
Я використовував підхід Nicks - мені потрібно було перевірити, чи встановлені віддалені інструменти для 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;
}
Моя вимога - перевірити, чи встановлене в моїй системі певне програмне забезпечення. Це рішення працює належним чином. Це може вам допомогти. Я використовував програму 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;
}