如何使用C#代码在系统中安装应用程序?
Answers:
遍历注册表项“ 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组件和更新,这可能对您很方便。
您可以看一下这篇文章。它利用注册表来读取已安装应用程序的列表。
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安装中的所有应用程序,以及Windows 64位安装中的64位应用程序。
为了还可以在Windows 64位安装上查看安装的32位应用程序,还需要枚举key @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
。
regedit
这看来。在32位的程序(在64位Windows),然而,这两个列表是相同的 WOW6432Node
从一个regedit
。
我希望能够像在开始菜单中一样提取应用程序列表。使用注册表,我得到的条目没有显示在开始菜单中。
我还想找到exe路径并提取一个图标,最终使它看起来很不错。不幸的是,对于注册表方法,这是一种偶然,因为我的观察是无法可靠地获得此信息。
我的替代方案基于shell:AppsFolder,您可以通过运行explorer.exe shell:appsFolder
该程序进行访问,并列出当前安装的所有应用程序,包括商店应用程序,这些应用程序可通过开始菜单使用。问题在于,这是一个虚拟文件夹,无法使用进行访问System.IO.Directory
。相反,您将必须使用本机shell32命令。幸运的是,Microsoft在Nuget上发布了Microsoft.WindowsAPICodePack-Shell,它是上述命令的包装。够了,这里是代码:
// 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用于在任务栏中将窗口分组的唯一ID。
AllEvents
例如ItemCreated
或ItemRenamed
我尝试使用它们来跟踪应用程序的安装或删除情况。这些事件的事件args包含一个Path
属性,但至少在我的测试中,此属性始终为null。我一直在试图弄清楚如何从中获取解析名称,因为它始终为null。取而代之的是,我只是保留了一个应用程序列表,只要在项目出现时通过迭代文件夹中的应用程序就可以同步这些应用程序。不理想,但可以完成工作。
值得注意的是Win32_Product WMI类代表Windows Installer安装的产品。并非每个应用程序都使用Windows Installer
但是,“ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall”表示32位的应用程序。对于64位,您还需要遍历“ HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall”,并且由于并非每个软件都具有64位版本,因此安装的总应用程序是两个位置都具有“ UninstallString”的键的并集重视他们。
但是最好的选择保持不变。遍历注册表项是一种更好的方法,因为每个应用程序都在注册表中有一个条目(包括Windows Installer中的条目)。但是,注册表方法是不安全的,好像有人删除了相应的项,那么您将不知道相反,更改HKEY_Classes_ROOT \ Installers则比较棘手,因为它与许可问题(例如Microsoft Office或其他产品)相关联。要获得更强大的解决方案,您始终可以将注册表替代方案与WMI结合使用。
虽然公认的解决方案有效,但是它并不完整。到目前为止。
如果要获取所有密钥,则需要再考虑两件事:
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)
{ }
}
}
}
}
}
使用Windows Installer API!
它允许对所有程序进行可靠的枚举。注册表不可靠,但是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安装。下面是我的解决方案。它创建一个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 Management Instrumentation)。如果将System.Management引用添加到C#项目,则可以访问类“ ManagementObjectSearcher”,您可能会发现它很有用。
对于已安装的应用程序,有各种WMI类,但是如果它是与Windows Installer一起安装的,则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;
}
我的要求是检查系统中是否安装了特定软件。此解决方案按预期方式工作。它可能会帮助您。我在Visual Studio 2015的c#中使用了Windows应用程序。
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;
}