C#获取已安装软件列表

最近项目需要判断目标电脑是否安装了对应环境,故需要获取系统上已安装的软件列表。查找一番,写下本篇文章备忘。
参考链接:
Registry 类
RegistryKey 类
RegistryView 枚举

Registry

提供表示 Windows 注册表中的根项的 RegistryKey 对象,并提供访问项/值对的 static 方法。

字段

ClassesRoot 定义文档的类型(或类)以及与那些类型关联的属性。 该字段读取 Windows 注册表基项 HKEY_CLASSES_ROOT。
CurrentConfig 包含有关非用户特定的硬件的配置信息。 该字段读取 Windows 注册表基项 HKEY_CURRENT_CONFIG。
CurrentUser 包含有关当前用户首选项的信息。 此字段读取 Windows 注册表基项 HKEY_CURRENT_USER。
LocalMachine 包含本地计算机的配置数据。 该字段读取 Windows 注册表基项 HKEY_LOCAL_MACHINE。
PerformanceData 包含软件组件的性能信息。 该字段读取 Windows 注册表基项 HKEY_PERFORMANCE_DATA。
Users 包含有关默认用户配置的信息。 该字段读取 Windows 注册表基项 HKEY_USERS。

RegistryKey

表示 Windows 注册表中的项级节点。 此类是注册表封装。

属性

Handle 获取一个 SafeRegistryHandle 对象,该对象表示当前 RegistryKey 对象封装的注册表项。
Name 检索项的名称。
SubKeyCount 检索当前项的子项计数。
ValueCount 检索项中值的计数。
View 获取用于创建注册表项的视图。

方法

Close() 关闭该项,如果其内容已修改,则将其刷新到磁盘。
CreateObjRef(Type) 创建一个对象,该对象包含生成用于与远程对象进行通信的代理所需的全部相关信息。(继承自 MarshalByRefObject)
CreateSubKey(String) 创建一个新子项或打开一个现有子项以进行写访问
CreateSubKey(String, Boolean) 创建一个新子项或打开具有指定访问权限的现有子项。 从 .NET Framework 4.6 开始可用。
CreateSubKey(String, Boolean, RegistryOptions) 创建一个新子项或打开具有指定访问权限的现有子项。 从 .NET Framework 4.6 开始可用。
CreateSubKey(String, RegistryKeyPermissionCheck) 使用指定的权限检查选项创建一个新子项或打开一个现有子项以进行写访问。
CreateSubKey(String, RegistryKeyPermissionCheck, RegistryOptions) 使用指定的权限检查和注册表选项,创建或打开一个用于写访问的子项。
CreateSubKey(String, RegistryKeyPermissionCheck, RegistryOptions, RegistrySecurity) 使用指定的权限检查选项、注册表选项和注册表安全性,创建或打开一个用于写访问的子项。
CreateSubKey(String, RegistryKeyPermissionCheck, RegistrySecurity) 使用指定的权限检查选项和注册表安全性创建一个新子项或打开一个现有子项以进行写访问。
DeleteSubKey(String) 删除指定子项。
DeleteSubKey(String, Boolean) 删除指定的子项,并指定在找不到该子项时是否引发异常。
DeleteSubKeyTree(String) 递归删除子项和任何子级子项。
DeleteSubKeyTree(String, Boolean) 以递归方式删除指定的子项和任何子级子项,并指定在找不到子项时是否引发异常。
DeleteValue(String) 从此项中删除指定值。
DeleteValue(String, Boolean) 从此项中删除指定的值,并指定在找不到该值时是否引发异常。
Dispose() 释放 RegistryKey 类的当前实例所使用的所有资源。
Equals(Object) 确定指定对象是否等于当前对象。(继承自 Object)
Flush() 将指定的打开注册表项的全部特性写到注册表中。
FromHandle(SafeRegistryHandle) 根据指定的句柄创建注册表项。
FromHandle(SafeRegistryHandle, RegistryView) 利用指定的句柄和注册表视图设置创建注册表项。
GetAccessControl() 返回当前注册表项的访问控制安全性。
GetAccessControl(AccessControlSections) 返回当前注册表项的访问控制安全性的指定部分。
GetHashCode() 作为默认哈希函数(继承自 Object)
GetSubKeyNames() 检索包含所有子项名称的字符串数组。
GetType() 获取当前实例的 Type。(继承自 Object)
GetValue(String) 检索与指定名称关联的值。 如果注册表中不存在名称/值对,则返回 null。
GetValue(String, Object) 检索与指定名称关联的值。 如果未找到名称,则返回你提供的默认值。
GetValue(String, Object, RegistryValueOptions) 检索与指定的名称和检索选项关联的值。 如果未找到名称,则返回你提供的默认值。
GetValueKind(String) 检索与指定名称关联的值的注册表数据类型。
GetValueNames() 检索包含与此项关联的所有值名称的字符串数组。
MemberwiseClone() 创建当前 Object 的浅表副本。(继承自 Object)
MemberwiseClone(Boolean) 创建当前 MarshalByRefObject 对象的浅表副本。(继承自 MarshalByRefObject)
OpenBaseKey(RegistryHive, RegistryView) 打开一个新的 RegistryKey,它使用指定的视图在本地计算机上表示请求的项。
OpenRemoteBaseKey(RegistryHive, String) 打开一个新的 RegistryKey,它表示远程计算机上的请求的项。
OpenRemoteBaseKey(RegistryHive, String, RegistryView) 打开一个新的注册表项,它使用指定的视图在远程计算机上表示请求的项。
OpenSubKey(String) 以只读方式检索子项。
OpenSubKey(String, Boolean) 检索指定的子项,并指定是否将写访问权限应用于该项。
OpenSubKey(String, RegistryKeyPermissionCheck) 检索指定的子项以进行读取或读/写访问。
OpenSubKey(String, RegistryKeyPermissionCheck, RegistryRights) 检索指定的子项以进行读取或读/写访问,请求指定的访问权限。
OpenSubKey(String, RegistryRights) 检索具有指定名称和访问权限的子项。 从 .NET Framework 4.6 开始可用。
SetAccessControl(RegistrySecurity) 向现有注册表项应用 Windows 访问控制安全性。
SetValue(String, Object) 设置指定的名称/值对。
SetValue(String, Object, RegistryValueKind) 使用指定的注册表数据类型设置注册表项中的名称/值对的值。
ToString() 检索此项的字符串表示形式。

RegistryView

指定要在 64 位操作系统上针对的注册表视图。

在 64 位版本的 Windows 上,注册表的某些部分分别存储于 32 位和 64 位应用程序。 32 位应用程序有 32 位视图,64 位应用程序有 64 位视图。

使用 OpenBaseKey 和 OpenRemoteBaseKey(RegistryHive, String, RegistryView) 方法以及 对象上的 RegistryKey 属性时,FromHandle可以指定注册表视图。

如果在 32 位操作系统上请求 64 位视图,则返回的密钥将位于 32 位视图中。

获取已安装软件列表

已安装软件的列表信息存储在注册表的”HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall”和”HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall”里。
在64位系统上,使用var subKey = Registry.LocalMachine.OpenSubKey();方法取得的RegistryKey.View为RegistryView.Registry64,在我电脑上获取的软件数量比RegistryKey.View=RegistryView.Registry32的少一些,但是用于判断软件环境足够了。

简单的获取软件列表如下(未做重名处理):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const string KeyPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
public static void Test1()
{
int softCnt = 0;
var subKey = Registry.LocalMachine.OpenSubKey(KeyPath, false);
var subKeyNames = subKey.GetSubKeyNames();
softCnt += subKeyNames.Length;
foreach (var name in subKeyNames)
{
RegistryKey tmp = subKey.OpenSubKey(name, false);
string displayName = tmp.GetValue("DisplayName") as string;
Console.WriteLine(displayName);
;
}
subKey = Registry.CurrentUser.OpenSubKey(KeyPath, false);
subKeyNames = subKey.GetSubKeyNames();
softCnt += subKeyNames.Length; ;
foreach (var name in subKeyNames)
{
RegistryKey tmp = subKey.OpenSubKey(name, false);
string displayName = tmp.GetValue("DisplayName") as string;
Console.WriteLine(displayName);
;
}
Console.WriteLine("all software count:" + softCnt);
}

通过指定32位和64位环境,获取比较全面的软件列表如下:(未作重名处理)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const string KeyPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
static int PrintSoftLst(RegistryKey subKey)
{
int softCnt = 0;
subKey = subKey.OpenSubKey(KeyPath, false);
var subKeyNames = subKey.GetSubKeyNames();
softCnt += subKeyNames.Length;
foreach (var name in subKeyNames)
{
RegistryKey tmp = subKey.OpenSubKey(name, false);
string displayName = tmp.GetValue("DisplayName") as string;
Console.WriteLine(displayName);
;
}
Console.WriteLine(subKey.View + ": " + softCnt);
return softCnt;
}
public static void Test2()
{
var subKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
PrintSoftLst(subKey);
subKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
PrintSoftLst(subKey);

subKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
PrintSoftLst(subKey);
subKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32);
PrintSoftLst(subKey);
}