检查注册表中是否安装了应用程序
本文关键字:应用程序 安装 是否 注册表 检查 | 更新日期: 2023-09-27 18:12:04
现在我用这个来列出注册表中列出的所有32位&64.我已经看到了其他的例子,如何检查一个应用程序是否安装没有任何运气。
string registryKey = @"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall";
RegistryKey key = Registry.LocalMachine.OpenSubKey(registryKey);
if (key != null)
{
foreach (String a in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(a);
Console.WriteLine(subkey.GetValue("DisplayName"));
}
}
registryKey = @"SOFTWARE'Wow6432Node'Microsoft'Windows'CurrentVersion'Uninstall";
key = Registry.LocalMachine.OpenSubKey(registryKey);
if (key != null)
{
foreach (String a in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(a);
Console.WriteLine(subkey.GetValue("DisplayName"));
}
}
所以这个片段在控制台窗口中列出了所有这些,我要做的是只要从显示名称列表中找到一个程序标题,看看它是否已安装。
我最后一次尝试的是
if (subkey.Name.Contains("OpenSSL"))
Console.Writeline("OpenSSL Found");
else
Console.Writeline("OpenSSL Not Found");
我尝试的任何东西都返回假或假阳性。有人能告诉我如何从列表中抓取标题吗?
请不要发布众所周知的私有静态void IsApplicationInstalled(p_name)函数。
经过搜索和故障排除,我让它这样工作:
public static bool checkInstalled (string c_name)
{
string displayName;
string registryKey = @"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall";
RegistryKey key = Registry.LocalMachine.OpenSubKey(registryKey);
if (key != null)
{
foreach (RegistryKey subkey in key.GetSubKeyNames().Select(keyName => key.OpenSubKey(keyName)))
{
displayName = subkey.GetValue("DisplayName") as string;
if (displayName != null && displayName.Contains(c_name))
{
return true;
}
}
key.Close();
}
registryKey = @"SOFTWARE'Wow6432Node'Microsoft'Windows'CurrentVersion'Uninstall";
key = Registry.LocalMachine.OpenSubKey(registryKey);
if (key != null)
{
foreach (RegistryKey subkey in key.GetSubKeyNames().Select(keyName => key.OpenSubKey(keyName)))
{
displayName = subkey.GetValue("DisplayName") as string;
if (displayName != null && displayName.Contains(c_name))
{
return true;
}
}
key.Close();
}
return false;
}
使用
if(checkInstalled("Application Name"))
这是一种干净的方法,不需要那么多代码。
private static bool IsSoftwareInstalled(string softwareName)
{
var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall") ??
Registry.LocalMachine.OpenSubKey(
@"SOFTWARE'Wow6432Node'Microsoft'Windows'CurrentVersion'Uninstall");
if (key == null)
return false;
return key.GetSubKeyNames()
.Select(keyName => key.OpenSubKey(keyName))
.Select(subkey => subkey.GetValue("DisplayName") as string)
.Any(displayName => displayName != null && displayName.Contains(softwareName));
}
用if语句调用:
if (IsSoftwareInstalled("OpenSSL"))
我检查了@Stellan Lindell的代码,它在所有情况下都不起作用。我的版本应该可以在所有场景下工作,并检查安装程序的特定版本(x86, x64)。
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Win32;
namespace Test
{
internal class Program
{
public enum ProgramVersion
{
x86,
x64
}
private static IEnumerable<string> GetRegisterSubkeys(RegistryKey registryKey)
{
return registryKey.GetSubKeyNames()
.Select(registryKey.OpenSubKey)
.Select(subkey => subkey.GetValue("DisplayName") as string);
}
private static bool CheckNode(RegistryKey registryKey, string applicationName, ProgramVersion? programVersion)
{
return GetRegisterSubkeys(registryKey).Any(displayName => displayName != null
&& displayName.Contains(applicationName)
&& displayName.Contains(programVersion.ToString()));
}
private static bool CheckApplication(string registryKey, string applicationName, ProgramVersion? programVersion)
{
RegistryKey key = Registry.LocalMachine.OpenSubKey(registryKey);
if (key != null)
{
if (CheckNode(key, applicationName, programVersion))
return true;
key.Close();
}
return false;
}
public static bool IsSoftwareInstalled(string applicationName, ProgramVersion? programVersion)
{
string[] registryKey = new [] {
@"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall",
@"SOFTWARE'Wow6432Node'Microsoft'Windows'CurrentVersion'Uninstall"
};
return registryKey.Any(key => CheckApplication(key, applicationName, programVersion));
}
private static void Main()
{
// Examples
Console.WriteLine("Notepad++: " + IsSoftwareInstalled("Notepad++", null));
Console.WriteLine("Notepad++(x86): " + IsSoftwareInstalled("Notepad++", ProgramVersion.x86));
Console.WriteLine("Notepad++(x64): " + IsSoftwareInstalled("Notepad++", ProgramVersion.x64));
Console.WriteLine("Microsoft Visual C++ 2009: " + IsSoftwareInstalled("Microsoft Visual C++ 2009", null));
Console.WriteLine("Microsoft Visual C-- 2009: " + IsSoftwareInstalled("Microsoft Visual C-- 2009", null));
Console.WriteLine("Microsoft Visual C++ 2013: " + IsSoftwareInstalled("Microsoft Visual C++ 2013", null));
Console.WriteLine("Microsoft Visual C++ 2012 Redistributable (x86): " + IsSoftwareInstalled("Microsoft Visual C++ 2013", ProgramVersion.x86));
Console.WriteLine("Microsoft Visual C++ 2012 Redistributable (x64): " + IsSoftwareInstalled("Microsoft Visual C++ 2013", ProgramVersion.x64));
Console.ReadKey();
}
}
}
解决方案@Hyperion是可以的,但它有一个错误,因为32位配置。不返回64位寄存器。要接收64位寄存器,执行以下操作:
string registryKey = @"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall";
RegistryKey key64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey key = key64.OpenSubKey(registryKey);
以上解决方案确实很好,但有时您必须检查产品是否也安装在另一台机器上。所以有一个版本是基于上面来自@Stellan Lindell和@Mroczny Arturek的解决方案
此方法适用于本地机器和远程机器…
public static bool IsSoftwareInstalled(string softwareName, string remoteMachine = null, StringComparison strComparison = StringComparison.Ordinal)
{
string uninstallRegKey = @"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall";
RegistryView[] enumValues = (RegistryView[])Enum.GetValues(typeof(RegistryView));
//Starts from 1, because first one is Default, so we dont need it...
for (int i = 1; i < enumValues.Length; i++)
{
//This one key is all what we need, because RegView will do the rest for us
using (RegistryKey key = (string.IsNullOrWhiteSpace(remoteMachine))
? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, enumValues[i]).OpenSubKey(uninstallRegKey)
: RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, remoteMachine, enumValues[i]).OpenSubKey(uninstallRegKey))
{
if (key != null)
{
if (key.GetSubKeyNames()
.Select(keyName => key.OpenSubKey(keyName))
.Select(subKey => subKey.GetValue("DisplayName") as string)
//SomeTimes we really need the case sensitive/insensitive option...
.Any(displayName => displayName != null && displayName.IndexOf(softwareName, strComparison) >= 0))
{ return true; }
}
}
}
return false;
}
注册表版本只是两个标准选项中的一个。另一种选择是使用WMI,但由于性能的原因,注册表要好得多,所以只将WMI作为一种选择。
//This one does't have a case sensitive/insesitive option, but if you need it, just don't use LIKE %softwareName%
//and get all products (SELECT Name FROM Win32_Product). After that just go trough the result and compare...
public static bool IsSoftwareInstalledWMI(string softwareName, string remoteMachine = null)
{
string wmiPath = (!string.IsNullOrEmpty(remoteMachine))
? @"''" + remoteMachine + @"'root'cimv2"
: @"''" + Environment.MachineName + @"'root'cimv2";
SelectQuery select = new SelectQuery(string.Format("SELECT * FROM Win32_Product WHERE Name LIKE '"%{0}%'"", softwareName));
if (SelectStringsFromWMI(select, new ManagementScope(wmiPath)).Count > 0) { return true; }
return false;
}
有我的SelectStringsFromWMI方法,但你可以自己做到这一点,这不是这个解决方案的重要部分。但是如果你感兴趣的话,这里有…
public static List<Dictionary<string, string>> SelectStringsFromWMI(SelectQuery select, ManagementScope wmiScope)
{
List<Dictionary<string, string>> result = new List<Dictionary<string, string>>();
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmiScope, select))
{
using (ManagementObjectCollection objectCollection = searcher.Get())
{
foreach (ManagementObject managementObject in objectCollection)
{
//With every new object we add new Dictionary
result.Add(new Dictionary<string, string>());
foreach (PropertyData property in managementObject.Properties)
{
//Always add data to newest Dictionary
result.Last().Add(property.Name, property.Value?.ToString());
}
}
return result;
}
}
}
! !更新! !
由于非常糟糕的性能,有另一个改进。
public static bool IsSoftwareInstalled(string softwareName, string remoteMachine = null, StringComparison strComparison = StringComparison.Ordinal)
{
string uninstallRegKey = @"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall";
RegistryView[] enumValues = (RegistryView[])Enum.GetValues(typeof(RegistryView));
//Starts from 1, because first one is Default, so we dont need it...
for (int i = 1; i < enumValues.Length; i++)
{
//This one key is all what we need, because RegView will do the rest for us
using (RegistryKey regKey = (string.IsNullOrWhiteSpace(remoteMachine))
? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, enumValues[i]).OpenSubKey(uninstallRegKey)
: RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, remoteMachine, enumValues[i]).OpenSubKey(uninstallRegKey))
{
if (SearchSubKeysForValue(regKey, "DisplayName", softwareName, strComparison).Result)
{ return true; }
}
}
return false;
}
和SearchSubKeysForValue方法(可以作为扩展方法构建):
public static async Task<bool> SearchSubKeysForValue(RegistryKey regKey, string valueName, string searchedValue, StringComparison strComparison = StringComparison.Ordinal)
{
bool result = false;
string[] subKeysNames = regKey.GetSubKeyNames();
List<Task<bool>> tasks = new List<Task<bool>>();
for (int i = 0; i < subKeysNames.Length - 1; i++)
{
//We have to save current value for i, because we cannot use it in async task due to changed values for it during foor loop
string subKeyName = subKeysNames[i];
tasks.Add(Task.Run(() =>
{
string value = regKey.OpenSubKey(subKeyName)?.GetValue(valueName)?.ToString() ?? null;
return (value != null && value.IndexOf(searchedValue, strComparison) >= 0);
}));
}
bool[] results = await Task.WhenAll(tasks).ConfigureAwait(false);
result = results.Contains(true);
return result;
}
这是我的64位版本
public static string[] checkInstalled(string findByName)
{
string[] info = new string[3];
string registryKey = @"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall";
//64 bits computer
RegistryKey key64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey key = key64.OpenSubKey(registryKey);
if (key != null)
{
foreach (RegistryKey subkey in key.GetSubKeyNames().Select(keyName => key.OpenSubKey(keyName)))
{
string displayName = subkey.GetValue("DisplayName") as string;
if (displayName != null && displayName.Contains(findByName))
{
info[0] = displayName;
info[1] = subkey.GetValue("InstallLocation").ToString();
info[2] = subkey.GetValue("Version").ToString();
}
}
key.Close();
}
return info;
}
你可以像这样调用这个方法
string[] JavaVersion = Software.checkInstalled("Java(TM) SE Development Kit");
如果数组为空则表示没有找到安装。如果它不是空的,它会给你原始名称,相对路径和位置,在大多数情况下,这就是我们想要得到的。
我在这里尝试了解决方案,但在某些情况下它们不起作用。原因是,我的程序是32位的,运行在64位的Windows上。通过这里发布的解决方案,32位进程无法检查是否安装了64位应用程序。
如何使用32位进程访问64位注册表
RegistryKey。OpenBaseKey
我修改了这里的解决方案,以得到一个工作的一个这个问题:
Console.WriteLine(IsSoftwareInstalled("Notepad++"));
public static bool IsSoftwareInstalled(string softwareName)
{
var registryUninstallPath = @"SOFTWARE'Microsoft'Windows'CurrentVersion'Uninstall";
var registryUninstallPathFor32BitOn64Bit = @"SOFTWARE'Wow6432Node'Microsoft'Windows'CurrentVersion'Uninstall";
if (Is32BitWindows())
return IsSoftwareInstalled(softwareName, RegistryView.Registry32, registryUninstallPath);
var is64BitSoftwareInstalled = IsSoftwareInstalled(softwareName, RegistryView.Registry64, registryUninstallPath);
var is32BitSoftwareInstalled = IsSoftwareInstalled(softwareName, RegistryView.Registry64, registryUninstallPathFor32BitOn64Bit);
return is64BitSoftwareInstalled || is32BitSoftwareInstalled;
}
private static bool Is32BitWindows() => Environment.Is64BitOperatingSystem == false;
private static bool IsSoftwareInstalled(string softwareName, RegistryView registryView, string installedProgrammsPath)
{
var uninstallKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView)
.OpenSubKey(installedProgrammsPath);
if (uninstallKey == null)
return false;
return uninstallKey.GetSubKeyNames()
.Select(installedSoftwareString => uninstallKey.OpenSubKey(installedSoftwareString))
.Select(installedSoftwareKey => installedSoftwareKey.GetValue("DisplayName") as string)
.Any(installedSoftwareName => installedSoftwareName != null && installedSoftwareName.Contains(softwareName));
}