Отримуйте встановлені програми в системі


Відповіді:


115

Ітерація через ключ реєстру "ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ \ 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, які можуть вам стати в нагоді.


27
Варто зазначити, що використання класу WMI Win32_Product - погана ідея, якщо ви плануєте запускати цей запит неодноразово. Перегляньте цю статтю в базі знань Microsoft: support.microsoft.com/kb/974524/EN-US Основна проблема полягає в тому, що (a) Win32_Product дійсно повільний і (b) створює "Інсталятор Windows, переконфігурований продукт". повідомлення журналу подій для кожного встановленого продукту у вашій системі ... кожного разу, коли ви запускаєте запит. Дох! Ця стаття рекомендує використовувати клас Win32reg_AddRemovePrograms ..., який відсутній, якщо ви не встановили SMS. Дох! Тож, мабуть, краще дотримуватися запиту реєстру.
Саймон Гіллбі

Коментар Саймона Гіллбі повинен бути прийнятою відповіддю, або Кіртанс! WMI WIN32_Product - не шлях сюди, повірте мені!
bdd

13
Е-е, ось чому приклад реєстру є першим у моїй відповіді. WMI був представлений просто як альтернативне рішення, і навіть там я стверджую, що "це виконується досить повільніше" та інші недоліки. Прочитайте відповідь з самого початку. ;)
Сяофу

1
Дивно, але якщо ви видалите програму та встановите її назад, спробуйте знайти її за допомогою ключів реєстру, якщо не перезапустите машину
Яр,

3
Щоб відповісти на моє власне запитання: stackoverflow.com/questions/27838798/ ... Хоча це дратує, що, можливо, доведеться запитувати як 64-бітну, так і 32-бітну.
Robert Koernke

9

Ви можете поглянути на цю статтю . Він використовує реєстр для читання списку встановлених програм.

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)
                { }
            }
        }
    }
}

Я не хочу цілого списку, мені потрібні лише вибрані програми для встановлення, щоб я для цього міг зробити. Дякую
Dhru 'soni

8

Я погоджуюся, що перелік за допомогою реєстру є найкращим способом.

Зверніть увагу , однак, що ключ заданий, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"буде список всіх додатків в 32-розрядної версії Windows , і 64-бітних додатків в 64-розрядної версії Windows.

Для того, щоб також бачити 32-розрядні програми, встановлені на 64-розрядної інсталяції Windows, вам також потрібно буде перерахувати ключ @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall".


Ви впевнені в цьому? На моїй Windows 10 Enterprise 64bit два списки схожі, і програми x86 відображаються в обох.
Флоріан Штрауб,

Дякую, це працює для мене, я знайшов програму, яку я шукав.
Xtian11

У regeditце так здається. Однак у 32-розрядної програмі (у 64-розрядної Windows) обидва списки ідентичні списку WOW6432Nodeз regedit.
Meow Cat 2012,

5

Я хотів мати можливість витягти список програм так само, як вони з’являються в меню «Пуск». Використовуючи реєстр, я отримував записи, які не відображаються в меню «Пуск».

Я також хотів знайти шлях до 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 використовує для групування вікон на панелі завдань .


Щиро дякую, дійсно хороший спосіб досягти цього. Чи знали ви, чи є спосіб отримати ім'я, синтаксичний розбір і так далі безпосередньо з ShellObjectWatcher?
forlayo

Існують і інші типи подій , за винятком AllEventsтаких , як ItemCreatedабо ItemRenamedщо я намагався використовувати , щоб стежити за додатками , як вони були встановлені або видалені. Аргументи подій цих подій містять Pathвластивість, але ця властивість завжди має значення null, принаймні в моїх тестах. Натомість я просто зберігаю список програм, які синхронізую щоразу, коли елемент піднімається шляхом перебору програм у папці. Не ідеально, але виконує роботу.
user1969903

1
Дякую! Я фактично роблю те саме; також це допомогло мені в іншому питанні про "як знайти основний виконуваний файл програми, яка була щойно встановлена" -> stackoverflow.com/questions/60440044/ ... Тоді дякую за це! :)
forlayo

4

Варто зазначити, що клас 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.


3

Поки прийняте рішення працює, воно не є повним. На багато.

Якщо ви хочете отримати всі ключі, вам слід взяти до уваги ще 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)
          { }
        }
      }
    }
  }
}

це працювало точніше, ніж інші рішення.
Вілас Джоші,

1

Переглядайте клавіші "HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" та перевіряйте їх значення "DisplayName".


1

Використовуйте API інсталятора Windows!

Це дозволяє зробити надійний перелік усіх програм. Реєстр не є надійним, але WMI є надважкою.


безумовно, це важка вага - при багаторазовому бігу ви побачите зниження продуктивності, як велика вага. якщо функція мого додатка залежить від іншої програми, і я знаю, чи встановлена ​​належним чином, мені потрібен лише ключ видалення реєстру для 32 або 64, лише якщо програма також доступна в 64 бітах), з іншого боку, якщо я повинен використовувати wmi, я обмежить використання лише один раз під час програми за допомогою трюку розумних властивостей.
gg89


1

Об'єкт для списку:

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")
                    });
                }
            }
        }
    }

1

Як зазначали інші, прийнята відповідь не повертає встановлення 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();
    }


0

Я можу запропонувати вам поглянути на WMI ( Інструментарій управління Windows ). Якщо ви додасте посилання System.Management до свого проекту C #, ви отримаєте доступ до класу `ManagementObjectSearcher ', який вам, мабуть, стане в нагоді.

Існують різні класи WMI для встановлених програм , але якщо він був встановлений за допомогою інсталятора Windows, то клас Win32_Product, мабуть, найкраще вам підходить.

ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM Win32_Product");

0

Я використовував підхід 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;
    }

0

Моя вимога - перевірити, чи встановлене в моїй системі певне програмне забезпечення. Це рішення працює належним чином. Це може вам допомогти. Я використовував програму 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;

        }

foreach (рядок subkey_name у key.GetSubKeyNames ()) <- Тут немає позначки, якщо значення null.
Burgo855

З цієї причини він не заслуговує голосу проти. Хоча це дублюється.
Meow Cat 2012,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.