Jak zainstalować aplikacje w systemie za pomocą kodu C #?
Odpowiedzi:
Wydaje się, że iteracja klucza rejestru „SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall” daje pełną listę zainstalowanych aplikacji.
Oprócz poniższego przykładu możesz znaleźć wersję podobną do tego, co zrobiłem tutaj .
To jest przybliżony przykład, prawdopodobnie będziesz chciał zrobić coś, aby usunąć puste wiersze, jak w drugim podanym łączu.
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"));
}
}
}
Alternatywnie możesz użyć WMI, jak wspomniano:
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach(ManagementObject mo in mos.Get())
{
Console.WriteLine(mo["Name"]);
}
Jest to jednak raczej wolniejsze do wykonania i słyszałem, że może wyświetlać tylko programy zainstalowane w „ALLUSERS”, chociaż może to być niepoprawne. Ignoruje również składniki i aktualizacje systemu Windows, które mogą być przydatne.
Możesz rzucić okiem na ten artykuł . Korzysta z rejestru, aby odczytać listę zainstalowanych aplikacji.
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)
{ }
}
}
}
}
Zgadzam się, że wyliczanie za pomocą klucza rejestru jest najlepszym sposobem.
Należy jednak pamiętać , że podany klucz @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
wyświetli listę wszystkich aplikacji w 32-bitowej instalacji systemu Windows i 64-bitowych w 64-bitowej instalacji systemu Windows.
Aby zobaczyć również aplikacje 32-bitowe zainstalowane w 64-bitowej instalacji systemu Windows, należałoby również wyliczyć klucz @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
.
regedit
to wygląda. Jednak w programie 32-bitowym (w 64-bitowym systemie Windows) obie listy są identyczne z listami WOW6432Node
z regedit
.
Chciałem mieć możliwość wyodrębnienia listy aplikacji tak, jak pojawiają się w menu Start. Korzystając z rejestru, otrzymywałem wpisy, które nie pojawiają się w menu Start.
Chciałem też znaleźć ścieżkę exe i wyodrębnić ikonę, aby ostatecznie stworzyć ładnie wyglądający program uruchamiający. Niestety, w przypadku metody rejestru jest to trochę chybione, ponieważ z moich obserwacji wynika, że informacje te nie są rzetelnie dostępne.
Moja alternatywa opiera się na powłoce: AppsFolder, do którego można uzyskać dostęp, uruchamiając explorer.exe shell:appsFolder
i który zawiera listę wszystkich aplikacji, w tym aplikacji sklepu, aktualnie zainstalowanych i dostępnych za pośrednictwem menu Start. Problem polega na tym, że jest to folder wirtualny, do którego nie można uzyskać dostępu System.IO.Directory
. Zamiast tego musiałbyś użyć natywnych poleceń shell32. Na szczęście Microsoft opublikował Microsoft.WindowsAPICodePack-Shell na Nuget, który jest opakowaniem dla wyżej wymienionych poleceń. Wystarczy powiedzieć, oto kod:
// 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;
}
I to wszystko. Możesz także uruchomić aplikacje za pomocą
System.Diagnostics.Process.Start("explorer.exe", @" shell:appsFolder\" + appModelUserID);
Działa to w przypadku zwykłych aplikacji Win32 i aplikacji ze sklepu UWP. A co z tymi jabłkami?
Ponieważ jesteś zainteresowany wyświetleniem wszystkich zainstalowanych aplikacji, rozsądnie jest oczekiwać, że możesz chcieć monitorować nowe aplikacje lub odinstalowane aplikacje, co możesz zrobić za pomocą ShellObjectWatcher
:
ShellObjectWatcher sow = new ShellObjectWatcher(appsFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();
Edycja: Można również chcieć wiedzieć, że wspomniany powyżej AppUserMoedlID jest unikalnym identyfikatorem używanym przez system Windows do grupowania okien na pasku zadań .
AllEvents
takich jak ItemCreated
lub ItemRenamed
które Próbowałem za pomocą śledzić aplikacje jak zostały one zainstalowane lub usunięte. Argumenty zdarzeń tych zdarzeń zawierają Path
właściwość, ale ta właściwość jest zawsze zerowa, przynajmniej w moich testach. Nie próbowałem dowiedzieć się, jak uzyskać z niej nazwę analizy, ponieważ jest ona zawsze pusta. Zamiast tego po prostu przechowuję listę aplikacji, które synchronizuję za każdym razem, gdy element zostanie podniesiony, iterując po aplikacjach w folderze. Nie jest idealny, ale wykonuje swoją pracę.
Warto zauważyć, że klasa WMI Win32_Product reprezentuje produkty, które są instalowane przez Instalatora Windows . nie każda aplikacja korzysta z instalatora Windows
jednakże „SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall” oznacza aplikacje dla wersji 32-bitowej. W przypadku wersji 64-bitowej należy również przejść przez „HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall”, a ponieważ nie każde oprogramowanie ma wersję 64-bitową, wszystkie zainstalowane aplikacje to suma kluczy w obu lokalizacjach z opcją „UninstallString” Wartość z nimi.
ale najlepsze opcje pozostają takie same. Traverse klucze rejestru są lepszym podejściem, ponieważ każda aplikacja ma wpis w rejestrze [w tym te w Instalatorze Windows]. jednak metoda rejestru jest niebezpieczna, ponieważ ktoś usunie odpowiedni klucz, nie będziesz wiedział Wręcz przeciwnie, zmiana klucza HKEY_Classes_ROOT \ Installers jest trudniejsza, ponieważ wiąże się z kwestiami licencyjnymi, takimi jak pakiet Microsoft Office lub inne produkty. aby uzyskać bardziej niezawodne rozwiązanie, zawsze możesz połączyć alternatywę rejestru z WMI.
Chociaż przyjęte rozwiązanie działa, nie jest kompletne. O wiele.
Jeśli chcesz zdobyć wszystkie klucze, musisz wziąć pod uwagę jeszcze 2 rzeczy:
Aplikacje x86 i x64 nie mają dostępu do tego samego rejestru. Zasadniczo x86 nie może normalnie uzyskać dostępu do rejestru x64. Niektóre aplikacje rejestrują się tylko w rejestrze x64.
i
niektóre aplikacje faktycznie instalują się w rejestrze CurrentUser zamiast w LocalMachine
Mając to na uwadze, udało mi się pobrać WSZYSTKIE zainstalowane aplikacje przy użyciu poniższego kodu, BEZ korzystania z WMI
Oto kod:
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)
{ }
}
}
}
}
}
Przejdź przez klucze „HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall” i sprawdź ich wartości „DisplayName”.
Użyj interfejsu API Instalatora Windows!
Pozwala na rzetelne wyliczenie wszystkich programów. Rejestr nie jest wiarygodny, ale WMI jest ciężki.
Obiekt do listy:
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; }
}
Wezwanie do stworzenia listy:
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")
});
}
}
}
}
Jak zauważyli inni, zaakceptowana odpowiedź nie zwraca zarówno instalacji x86, jak i x64. Poniżej znajduje się moje rozwiązanie. Tworzy StringBuilder
, dołącza do niego wartości rejestru (z formatowaniem) i zapisuje dane wyjściowe do pliku tekstowego:
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();
}
Najlepszym rozwiązaniem jest skorzystanie z WMI . W szczególności klasa Win32_Product .
Mogę zasugerować przyjrzenie się WMI ( Instrumentacja zarządzania Windows ). Jeśli dodasz odwołanie System.Management do projektu C #, uzyskasz dostęp do klasy `ManagementObjectSearcher ', która prawdopodobnie okaże się przydatna.
Istnieją różne klasy WMI dla zainstalowanych aplikacji , ale jeśli została zainstalowana za pomocą Instalatora Windows, to klasa Win32_Product prawdopodobnie najlepiej Ci odpowiada.
ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
Użyłem podejścia Nicka - musiałem sprawdzić, czy zdalne narzędzia dla Visual Studio są zainstalowane, czy nie, wydaje się to trochę powolne, ale w osobnym wątku jest to dla mnie w porządku. - tutaj mój rozszerzony kod:
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;
}
Moim wymaganiem jest sprawdzenie, czy w moim systemie jest zainstalowane określone oprogramowanie. To rozwiązanie działa zgodnie z oczekiwaniami. To może ci pomóc. Użyłem aplikacji Windows w języku C # z 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;
}