Получить установленные приложения в системе

Ответы:

116

Итерации по разделу реестра «SOFTWARE \ 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 Основная проблема заключается в том, что (а) Win32_Product работает очень медленно и (б) генерирует сообщение «Установщик Windows перенастроил продукт». сообщение журнала событий для каждого продукта, установленного в вашей системе ... каждый раз, когда вы запускаете запрос. Дох! В этой статье рекомендуется использовать класс Win32reg_AddRemovePrograms ... которого нет, если вы не установили SMS. Дох! Так что, вероятно, лучше придерживаться запроса реестра.
Саймон Гиллби,
Комментарий Саймона Гиллби должен быть принятым ответом, или киртаном! WMI WIN32_Product - не лучший вариант, поверьте мне!
спб,
13
Эээ, поэтому пример реестра первый в моем ответе. WMI был представлен просто как альтернативное решение, и даже там я заявляю, что «он выполняется медленнее» и другие недостатки. Прочтите ответ с самого начала. ;)
Xiaofu
1
Довольно странно, но если вы удалите программу и установите ее обратно, а затем попытайтесь найти ее с помощью ключей реестра, вы не сможете, если не перезагрузите компьютер
Яр
3
Чтобы ответить на свой вопрос: stackoverflow.com/questions/27838798/… Хотя раздражает то, что вам, возможно, придется запрашивать как 64-битные, так и 32-битные версии.
Роберт Кёрнке
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
9

Я согласен, что лучше всего использовать раздел реестра.

Обратите внимание , однако, что указанный ключ @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", будет перечислять все приложения в 32-битной установке Windows и 64-битные приложения в 64-битной установке Windows.

Чтобы также видеть 32-разрядные приложения, установленные в 64-разрядной версии Windows, вам также потребуется перечислить ключ @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall".

Стивен Уолтер
источник
Ты уверен насчет этого? На моей 64-битной Windows 10 Enterprise два списка выглядят одинаково, и приложения x86 отображаются в обоих.
Флориан Штрауб
Спасибо, у меня это работает, я нашел программу, которую искал.
Xtian11
В regeditэто так кажется. Однако в 32-битной программе (в 64-битной Windows) оба списка идентичны WOW6432Nodeсписку из regedit.
Meow Cat 2012
6

Я хотел иметь возможность извлекать список приложений так, как они отображаются в меню «Пуск». Используя реестр, я получал записи, которые не отображались в меню «Пуск».

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

user1969903
источник
Большое спасибо, действительно хороший способ добиться этого. Знаете ли вы, есть ли способ получить имя, имя синтаксического анализа или что-то подобное непосредственно из ShellObjectWatcher?
forlayo
Существуют и другие типы событий , за исключением AllEventsтаких , как ItemCreatedили ItemRenamedкоторый я пытался использовать , чтобы следить за приложениями , как они были установлены или удалены. Аргументы этих событий содержат Pathсвойство, но это свойство всегда имеет значение null, по крайней мере, в моих тестах. Я не стал пытаться выяснить, как получить из него имя синтаксического анализа, поскольку оно всегда равно null. Вместо этого я просто храню список приложений, которые синхронизирую всякий раз, когда возникает элемент, путем итерации по приложениям в папке. Не идеально, но выполняет свою работу.
user1969903
1
Благодаря! Я действительно делаю то же самое; также это помогло мне в другом вопросе о том, «как обнаружить основной исполняемый файл только что установленного приложения» -> stackoverflow.com/questions/60440044/… Тогда спасибо за это! :)
forlayo
4

Стоит отметить, что класс Win32_Product WMI представляет продукты, установленные установщиком Windows . не каждое приложение использует установщик Windows

однако "SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" представляет приложения для 32-битной версии. Для 64-битной версии вам также необходимо пройти через "HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall", и, поскольку не у каждого программного обеспечения есть 64-битная версия, все установленные приложения представляют собой объединение ключей в обоих местах, которые имеют "UninstallString" Цени с ними.

но лучшие варианты остаются теми же. поперечные ключи реестра - лучший подход, так как каждое приложение имеет запись в реестре [включая те, что находятся в установщике Windows]. однако метод реестра небезопасен, так как если кто-то удалит соответствующий ключ, вы не узнаете Напротив, изменение 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

Используйте Windows Installer API!

Это позволяет производить надежное перечисление всех программ. Реестр ненадежен, но 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. Ниже мое решение для этого. Он создает 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 - мне нужно было проверить, установлены ли Remote Tools для 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 (string subkey_name в key.GetSubKeyNames ()) <- Здесь нет проверки, если null.
Burgo855
Он не заслуживает голоса против по ЭТОЙ причине. Хотя дублируется.
Meow Cat 2012,