检查应用程序是否安装在注册表中

时间:2013-05-04 21:28:38

标签: c# c windows registry

现在我用它来列出注册表中列出的所有应用程序32bit& 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");

我尝试过的任何东西都是假的或误报。有没有人可以告诉我如何从列表中获取一个标题?

请不要发布众所周知的private static void IsApplicationInstalled(p_name)函数。它根本不适用于我。

7 个答案:

答案 0 :(得分:19)

在搜索和排除故障后,我让它以这种方式工作:

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"))

答案 1 :(得分:10)

如果没有那么多代码,这是一种干净的方法。

    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"))

答案 2 :(得分:6)

我已经检查了@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();
    }
}
}

答案 3 :(得分:3)

解决方案@Hyperion可以,但是由于32位配置,它有一个错误。没有返回64位寄存器。要接收64位寄存器,请执行以下操作:

string registryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
RegistryKey key64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey key = key64.OpenSubKey(registryKey);

答案 4 :(得分:0)

上面的解决方案确实不错,但是有时您必须检查产品是否也安装在另一台计算机上。因此,有一个基于上述@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;
    }

答案 5 :(得分:0)

我在这里尝试了解决方案,但是在某些情况下它们没有起作用。原因是,我的程序为32位,并且在64位Windows上运行。通过此处发布的解决方案, 32位进程无法检查是否安装了64位应用程序

How to access 64 bit registry with a 32 bit process

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));
    }

答案 6 :(得分:0)

这是我的64位版本

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    cell.textLabel?.text = "\([indexPath.row+1])"
    if !emptyA.contains(indexPath.row+1) {
        emptyA.append(indexPath.row+1)
    }
    return cell
}

您可以像这样调用此方法

  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;
    }

如果阵列为空,则表示未找到安装。如果不为空,它将为您提供原始名称,相对路径和位置,在大多数情况下,这就是我们希望获得的所有信息。