Holen Sie sich installierte Anwendungen in einem System


83

Wie werden die Anwendungen mithilfe von C # -Code im System installiert?

Antworten:


115

Das Durchlaufen des Registrierungsschlüssels "SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" scheint eine umfassende Liste der installierten Anwendungen zu ergeben.

Abgesehen von dem folgenden Beispiel finden Sie eine ähnliche Version wie hier .

Dies ist ein grobes Beispiel. Sie möchten wahrscheinlich etwas tun, um leere Zeilen wie im zweiten bereitgestellten Link zu entfernen.

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

Alternativ können Sie WMI wie folgt verwenden:

ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach(ManagementObject mo in mos.Get())
{
    Console.WriteLine(mo["Name"]);
}

Die Ausführung ist jedoch etwas langsamer, und ich habe gehört, dass möglicherweise nur unter "ALLUSERS" installierte Programme aufgelistet werden, obwohl dies möglicherweise falsch ist. Außerdem werden die Windows-Komponenten und -Updates ignoriert, die für Sie nützlich sein können.


27
Es ist erwähnenswert, dass die Verwendung der WMI Win32_Product-Klasse eine schlechte Idee ist, wenn Sie diese Abfrage wiederholt ausführen möchten. Siehe diesen Microsoft KB-Artikel: support.microsoft.com/kb/974524/EN-US Das Hauptproblem ist, dass (a) Win32_Product sehr langsam ist und (b) ein "Windows Installer hat das Produkt neu konfiguriert" generiert. Ereignisprotokollmeldung für jedes auf Ihrem System installierte Produkt ... jedes Mal, wenn Sie die Abfrage ausführen. Doh! In diesem Artikel wird empfohlen, die Win32reg_AddRemovePrograms-Klasse zu verwenden, die nur vorhanden ist, wenn Sie SMS installiert haben. Doh! Also wahrscheinlich besser bei der Registrierungsabfrage bleiben.
Simon Gillbee

Simon Gillbees Kommentar sollte die akzeptierte Antwort sein, oder Kirtans! WMI WIN32_Product ist nicht der richtige Weg, vertrau mir!
Bdd

13
Ähm, deshalb steht das Registrierungsbeispiel in meiner Antwort an erster Stelle. WMI wurde einfach als alternative Lösung vorgestellt, und selbst dort sage ich "dies ist eher langsamer auszuführen" und andere Nachteile. Lesen Sie die Antwort von Anfang an. ;)
Xiaofu

1
Irgendwie komisch , aber wenn Sie ein Programm deinstallieren und installieren Sie es zurück , dann versuchen Sie es Registrierungsschlüssel verwenden zu finden verwenden Sie nicht , wenn Sie Ihr Gerät neu starten
Yar

3
Um meine eigene Frage zu beantworten: stackoverflow.com/questions/27838798/… Obwohl es ärgerlich ist, dass Sie möglicherweise sowohl 64-Bit als auch 32-Bit abfragen müssen.
Robert Koernke

9

Sie können sich diesen Artikel ansehen . Es verwendet die Registrierung, um die Liste der installierten Anwendungen zu lesen.

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

Ich möchte keine ganze Liste, ich brauche nur einige ausgewählte Installationsprogramme. Was kann ich dafür tun? Vielen Dank
Dhru 'soni

8

Ich bin damit einverstanden, dass die Aufzählung über den Registrierungsschlüssel der beste Weg ist.

Beachten Sie jedoch, dass der angegebene Schlüssel@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" alle Anwendungen in einer 32-Bit-Windows-Installation und 64-Bit-Anwendungen in einer Windows 64-Bit-Installation auflistet.

Um auch 32-Bit-Anwendungen zu sehen, die in einer Windows 64-Bit-Installation installiert sind, müssen Sie auch den Schlüssel aufzählen @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall".


Bist du dir da sicher? Auf meinem Windows 10 Enterprise 64-Bit sehen die beiden Listen gleich aus und die x86-Anwendungen werden in beiden angezeigt.
Florian Straub

Danke, das funktioniert bei mir. Ich habe das Programm gefunden, nach dem ich gesucht habe.
Xtian11

Darin regeditscheint es so. In einem 32 - Bit - Programm (auf 64 - Bit - Windows) sind jedoch beide Listen identisch mit dem WOW6432Nodeeinem ausregedit .
Meow Cat 2012

6

Ich wollte in der Lage sein, eine Liste von Apps so zu extrahieren, wie sie im Startmenü angezeigt werden. Bei Verwendung der Registrierung wurden Einträge angezeigt, die nicht im Startmenü angezeigt werden.

Ich wollte auch den exe-Pfad finden und ein Symbol extrahieren, um schließlich einen gut aussehenden Launcher zu erstellen. Leider ist dies bei der Registrierungsmethode ein Hit und Miss, da ich feststelle, dass diese Informationen nicht zuverlässig verfügbar sind.

Meine Alternative basiert auf der Shell: AppsFolder, auf den Sie durch Ausführen zugreifen können explorer.exe shell:appsFolderund der alle Apps auflistet, einschließlich Store-Apps, die derzeit installiert sind und über das Startmenü verfügbar sind. Das Problem ist, dass dies ein virtueller Ordner ist, auf den nicht zugegriffen werden kann System.IO.Directory. Stattdessen müssten Sie native Shell32-Befehle verwenden. Glücklicherweise hat Microsoft die Microsoft.WindowsAPICodePack-Shell auf Nuget veröffentlicht, einem Wrapper für die oben genannten Befehle. Genug gesagt, hier ist der Code:

// 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;
}

Und das ist alles. Sie können die Apps auch mit starten

System.Diagnostics.Process.Start("explorer.exe", @" shell:appsFolder\" + appModelUserID);

Dies funktioniert für reguläre Win32-Apps und UWP-Store-Apps. Wie wäre es mit Äpfeln?

Da Sie daran interessiert sind, alle installierten Apps aufzulisten, ist zu erwarten, dass Sie auch nach neuen Apps oder deinstallierten Apps suchen möchten. Dies können Sie tun, indem Sie ShellObjectWatcher:

ShellObjectWatcher sow = new ShellObjectWatcher(appsFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();

Bearbeiten: Möglicherweise möchten Sie auch wissen, dass die oben erwähnte AppUserMoedlID die eindeutige ID ist, die Windows zum Gruppieren von Fenstern in der Taskleiste verwendet .


Vielen Dank, ein wirklich guter Weg, um dies zu erreichen. Wussten Sie, ob es eine Möglichkeit gibt, Namen, Parsing-Namen oder so direkt von ShellObjectWatcher abzurufen?
Forlayo

Es gibt auch andere Ereignistypen abgesehen von AllEventswie ItemCreatedoder ItemRenamedwo ich versuchte , mit Spur von Anwendungen zu halten , wie sie installiert oder entfernt wurden. Die Ereignisargumente dieser Ereignisse enthalten eine PathEigenschaft, aber diese Eigenschaft ist zumindest in meinen Tests immer null. Ich habe mich nicht darum gekümmert, herauszufinden, wie man einen Parsing-Namen daraus erhält, da sie immer null ist. Stattdessen behalte ich einfach eine Liste von Apps, die ich synchronisiere, wenn ein Element ausgelöst wird, indem ich die Apps im Ordner durchlaufe. Nicht ideal, aber erledigt den Job.
user1969903

1
Vielen Dank! Ich mache eigentlich das gleiche; Auch dies hat mir bei anderen Fragen geholfen, wie man die ausführbare Hauptdatei einer gerade installierten Anwendung erkennt -> stackoverflow.com/questions/60440044/… Dann danke dafür! :)
Forlayo

4

Es ist erwähnenswert, dass die WMI-Klasse Win32_Product Produkte darstellt, wie sie von Windows Installer installiert werden . Nicht jede Anwendung verwendet das Windows-Installationsprogramm

"SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" steht jedoch für 32-Bit-Anwendungen. Für 64-Bit müssen Sie außerdem "HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall" durchlaufen. Da nicht jede Software eine 64-Bit-Version hat, sind die insgesamt installierten Anwendungen eine Vereinigung von Schlüsseln an beiden Speicherorten mit "UninstallString". Wert mit ihnen.

Die besten Optionen bleiben jedoch die gleichen. Traverse-Registrierungsschlüssel sind ein besserer Ansatz, da jede Anwendung einen Eintrag in der Registrierung hat [einschließlich derjenigen in Windows Installer]. Die Registrierungsmethode ist jedoch unsicher, als ob jemand den entsprechenden Schlüssel entfernt, dann wissen Sie es nicht Der Anwendungseintrag. Im Gegenteil, das Ändern der HKEY_Classes_ROOT \ Installers ist schwieriger, da es mit Lizenzproblemen wie Microsoft Office oder anderen Produkten verbunden ist. Für eine robustere Lösung können Sie die Registrierungsalternative immer mit der WMI kombinieren.


3

Die akzeptierte Lösung funktioniert zwar, ist jedoch nicht vollständig. Bei weitem.

Wenn Sie alle Schlüssel erhalten möchten, müssen Sie zwei weitere Dinge berücksichtigen:

x86- und x64-Anwendungen haben keinen Zugriff auf dieselbe Registrierung. Grundsätzlich kann x86 normalerweise nicht auf die x64-Registrierung zugreifen. Einige Anwendungen registrieren sich nur in der x64-Registrierung.

und

Einige Anwendungen werden tatsächlich in der CurrentUser-Registrierung anstelle der LocalMachine installiert

In diesem Sinne habe ich es geschafft, ALLE installierten Anwendungen mit dem folgenden Code OHNE zu erhalten WMI zu verwenden

Hier ist der Code:

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

Dies funktionierte genauer als andere Lösungen.
Vilas Joshi

1

Durchlaufen Sie die Schlüssel "HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" und überprüfen Sie deren "DisplayName" -Werte.


1

Verwenden Sie die Windows Installer-API!

Es ermöglicht eine zuverlässige Aufzählung aller Programme. Die Registrierung ist nicht zuverlässig, aber WMI ist schwergewichtig.


Sicher ist schweres Gewicht - wenn man wiederholt läuft, sieht man Leistungseinbußen wie bei einem schweren Gewicht. Wenn eine Funktion meiner App von einer anderen App abhängt und weiß, ob sie ordnungsgemäß installiert ist, benötige ich den Registrierungsschlüssel für 32 oder 64 nur, wenn die App auch in 64-Bit verfügbar ist. Wenn ich wmi verwenden muss, I. beschränkt sich auf die einmalige Verwendung während einer Anwendung über einen Smart-Property-Trick.
gg89


1

Das Objekt für die Liste:

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

Der Aufruf zum Erstellen der Liste:

    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

Wie andere bereits betont haben, gibt die akzeptierte Antwort nicht sowohl x86- als auch x64-Installationen zurück. Unten ist meine Lösung dafür. Es erstellt ein StringBuilder, hängt die Registrierungswerte an (mit Formatierung) an und schreibt seine Ausgabe in eine Textdatei:

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

Könnte ich vorschlagen, dass Sie sich WMI ( Windows Management Instrumentation) ansehen ) . Wenn Sie Ihrem C # -Projekt den System.Management-Verweis hinzufügen, erhalten Sie Zugriff auf die Klasse "ManagementObjectSearcher", die Sie wahrscheinlich nützlich finden werden.

Es gibt verschiedene WMI-Klassen für installierte Anwendungen . Wenn sie jedoch mit Windows Installer installiert wurden, ist die Win32_Product-Klasse wahrscheinlich am besten für Sie geeignet.

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

0

Ich habe den Nicks-Ansatz verwendet. Ich musste überprüfen, ob die Remote Tools für Visual Studio installiert sind oder nicht. Es scheint etwas langsam zu sein, aber in einem separaten Thread ist dies für mich in Ordnung. - hier mein erweiterter Code:

    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

Ich muss überprüfen, ob auf meinem System bestimmte Software installiert ist. Diese Lösung funktioniert wie erwartet. Es könnte dir helfen. Ich habe eine Windows-Anwendung in c # mit Visual Studio 2015 verwendet.

 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 (Zeichenfolge subkey_name in key.GetSubKeyNames ()) <- Hier wird nicht geprüft, ob null.
Burgo855

Aus DIESEM Grund verdient es keine Ablehnung. Obwohl es dupliziert ist.
Meow Cat 2012
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.