在系统中获取已安装的应用程序

Sau*_*ron 72 .net c# installation installer

如何使用c#代码在系统中安装应用程序?

Xia*_*ofu 101

通过注册表项"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"));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用WMI,如上所述:

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

但执行速度相当慢,我听说它可能只列出"ALLUSERS"下安装的程序,尽管这可能不正确.它还忽略了Windows组件和更新,这对您来说可能很方便.

  • 值得注意的是,如果您计划重复运行此查询,那么使用WMI Win32_Product类是个坏主意.请参阅此Microsoft知识库文章:http://support.microsoft.com/kb/974524/EN-US核心问题是(a)Win32_Product非常慢,(b)它生成"Windows Installer重新配置产品".每次运行查询时,系统上*每个*已安装产品的事件日志消息... 卫生署!本文建议使用Win32reg_AddRemovePrograms类...除非您已安装SMS,否则该类不存在.卫生署!所以最好坚持使用注册表查询. (25认同)
  • 呃,这就是为什么注册表示例在我的答案中的第一个原因.WMI被简单地作为替代解决方案呈现,即使在那里我也说"执行速度相当慢"和其他缺点.从头开始阅读答案.;) (11认同)
  • 要回答我自己的问题:/sf/ask/1948715891/虽然很烦人,你可能要同时查询64位和32位. (3认同)

use*_*903 12

我希望能够提取出现在开始菜单中的应用程序列表。使用注册表,我得到的条目没有出现在开始菜单中。

我还想找到 exe 路径并提取一个图标以最终制作一个漂亮的启动器。不幸的是,使用注册表方法,这是一种命中和失误,因为我的观察是这些信息不可靠。

我的替代方案基于 shell:AppsFolder,您可以通过运行访问该文件夹,explorer.exe shell:appsFolder其中列出了当前安装的所有应用程序,包括商店应用程序,这些应用程序可通过开始菜单获得。问题是这是一个无法使用System.IO.Directory. 相反,您必须使用本机 shell32 命令。幸运的是,微软在 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;
}
Run Code Online (Sandbox Code Playgroud)

这就是全部。您还可以使用启动应用程序

System.Diagnostics.Process.Start("explorer.exe", @" shell:appsFolder\" + appModelUserID);
Run Code Online (Sandbox Code Playgroud)

这适用于常规 Win32 应用程序和 UWP 商店应用程序。他们苹果怎么样。

由于您有兴趣列出所有已安装的应用程序,因此有理由期望您可能还想监视新应用程序或已卸载的应用程序,您可以使用ShellObjectWatcher

ShellObjectWatcher sow = new ShellObjectWatcher(appsFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();
Run Code Online (Sandbox Code Playgroud)

编辑:人们可能还想知道上面提到的 AppUserMoedlID 是Windows 用于对 taskbar 中的窗口进行分组唯一 ID


Kir*_*tan 10

你可以看一下这篇文章.它使用注册表来读取已安装的应用程序列表.

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)
                { }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 8

我同意通过注册表项枚举是最好的方法.

但请注意,给定的密钥@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"将列出32位Windows安装中的所有应用程序,以及Windows 64位安装中的64位应用程序.

为了还能看到在Windows 64位安装上安装的32位应用程序,您还需要枚举密钥@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall".


Aks*_*ita 5

值得注意的是,Win32_Product WMI类代表Windows Installer安装的产品[ http://msdn.microsoft.com/en-us/library/aa394378%28v=vs.85%29.aspx].不是每个应用程序使用Windows安装程序

但是"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"表示32位应用程序.对于64位,您还需要遍历"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall",并且由于并非每个软件都具有64位版本,因此安装的总应用程序是两个位置上具有"UninstallString"的键的并集.值得他们.

但最好的选项仍然是相同的.traverse注册表项是一种更好的方法,因为每个应用程序在注册表中都有一个条目[包括Windows Installer中的条目].但是注册表方法是不安全的,好像有人删除了相应的密钥然后你就不会知道了应用程序条目.相反,更改HKEY_Classes_ROOT \安装程序更加棘手,因为它与Microsoft办公室或其他产品等许可问题相关联.对于更强大的解决方案,您始终可以将注册表替代与WMI结合使用.


Pic*_*ael 5

虽然接受的解决方案有效,但它并不完整。到目前为止。

如果你想获得所有的钥匙,你还需要考虑两件事:

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)
          { }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)