C# WMI-从Win32_产品中选择需要很长时间

C# WMI-从Win32_产品中选择需要很长时间,c#,wmi,wmi-query,C#,Wmi,Wmi Query,我正在使用WMI枚举已安装的应用程序,无论我如何构造它,完成此块都需要相对较长的时间。在我的环境中,每次需要13秒。是否有更好(更快)的方法检查程序是否已安装?(我用iTunes作为示例程序来检查) 从名称为“iTunes”的Win32_产品中选择* 0 - 08:14:17.6529 1 - 08:14:17.6709 2 - 08:14:17.6779 3 - 08:14:31.0332 Length - 1 0 - 08:16:38.2719 1 - 08:16:38.2899 2 -

我正在使用WMI枚举已安装的应用程序,无论我如何构造它,完成此块都需要相对较长的时间。在我的环境中,每次需要13秒。是否有更好(更快)的方法检查程序是否已安装?(我用iTunes作为示例程序来检查)

从名称为“iTunes”的Win32_产品中选择*

0 - 08:14:17.6529
1 - 08:14:17.6709
2 - 08:14:17.6779
3 - 08:14:31.0332
Length - 1
0 - 08:16:38.2719
1 - 08:16:38.2899
2 - 08:16:38.2999
3 - 08:16:51.5113
Length - 1
0 - 08:19:53.9144
1 - 08:19:53.9324
2 - 08:19:53.9394
3 - 08:20:07.2794
Length - 1
从名称类似“iTunes”的Win32\u产品中选择*

0 - 08:14:17.6529
1 - 08:14:17.6709
2 - 08:14:17.6779
3 - 08:14:31.0332
Length - 1
0 - 08:16:38.2719
1 - 08:16:38.2899
2 - 08:16:38.2999
3 - 08:16:51.5113
Length - 1
0 - 08:19:53.9144
1 - 08:19:53.9324
2 - 08:19:53.9394
3 - 08:20:07.2794
Length - 1
从Win32\u产品中选择名称,其中的名称类似于“iTunes”

0 - 08:14:17.6529
1 - 08:14:17.6709
2 - 08:14:17.6779
3 - 08:14:31.0332
Length - 1
0 - 08:16:38.2719
1 - 08:16:38.2899
2 - 08:16:38.2999
3 - 08:16:51.5113
Length - 1
0 - 08:19:53.9144
1 - 08:19:53.9324
2 - 08:19:53.9394
3 - 08:20:07.2794
Length - 1

WMI正在占用您已经注意到的时间。在注册表中进行迭代可能会对您有所帮助


您可以在这里查看stackoverflow,其中提到了这两种方法。

您应该在WMI查询中使用
从Win32\u产品中选择名称
,它对我有效

选择*
使加载所有数据成员,因此如果您查询“Win32_产品”msi安装程序将检查并验证每个产品,则使用它将花费大量时间。

知识库文章显示:

Win32_产品类未进行查询优化。诸如“select*from Win32_Product where(名称如“Sniffer%”)之类的查询要求WMI使用MSI提供程序枚举所有已安装的产品,然后按顺序解析完整列表以处理“where”子句。此过程还将启动已安装软件包的一致性检查,以验证和修复安装。使用仅具有用户权限的帐户时,由于该用户帐户可能无法访问多个位置,可能会导致应用程序启动延迟,并发生事件11708,表明安装失败

Win32reg_AddRemovePrograms是一种更轻、更有效的方法,它避免了执行弹性检查的调用,尤其是在锁定的环境中。因此,当使用Win32reg_AddRemovePrograms时,我们不会调用msiprov.dll,也不会启动弹性检查

所以要小心使用“Win32_产品”


更新:很好的文章

正如Bernhard指出的,使用Win32_产品的WMI会启动对软件包属性的完整性检查,因此使用起来会非常慢-在特殊情况下,它会触发MSI自修复(我从未在我的机器上看到这种情况)

您可以直接使用MSI自动化接口来枚举通过计算机上的Windows Installer软件包(MSI文件)安装的应用程序,而不是WMI。这是非常快的,根本不涉及WMI

请参见此示例:(完整但简单易懂的VBScript示例-请查看)。您可以为每个产品检索许多属性,请咨询。我希望链接的示例VBScript代码和MSDN文档能够帮助您快速开始

注:我知道这是一个老问题,但这个问题不断出现(特别是WMI的缓慢性)-仅供将来参考。

如前所述,注册表不可靠,WMI运行缓慢。因此,对我来说,最好的选择是使用Windows Installer API。将msi.dll添加到引用中,然后根据需要调整以下代码:

public static string GetVersionOfInstalledApplication(string queryName)
{
    string name;
    string version;
    Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
    Installer installer = Activator.CreateInstance(type) as Installer;
    StringList products = installer.Products;
    foreach (string productGuid in products)
    {
        string currName = installer.ProductInfo[productGuid, "ProductName"];
        string currVersion = installer.ProductInfo[productGuid, "VersionString"];
        if (currName == queryName)
        {
            name = currName;
            version = currVersion;
            return version;
        }
    }
    return null;
}

使用Win32Reg_AddRemovePrograms,必须安装fasterSMS server 2003才能使用Win32Reg_AddRemovePrograms,这是我无法强制执行的要求。通过注册表进行迭代的速度要快得多,虽然它有自己的细微差别,但我必须仔细研究,看看它是否是一个可行的选择。这最终是最好的解决方案,因为它a)更快,b)从win32_产品日志中进行选择,并为每个被查询的应用程序输入事件查看器,这对我的应用程序来说是一个不良的副作用,我已经添加了关于如何使用MSI自动化接口枚举已安装MSI文件的信息来回答这个问题。我只想指出,使用WMI的Win32_产品确实会启动对包状态的检查,但只有在发现不一致时才会触发自修复。我从来没有让这种情况发生在我的任何一个盒子上,但它可以发生。但总体而言WMI相当缓慢。它很有用,但如果可以的话,可以使用其他工具。使用WMI Win32_产品的替代方案?