枚举已安装产品的升级代码



我想获得Windows盒子上所有已安装产品的所有升级代码列表。问题是:是否有专门的MSI功能来处理此请求?

MsiEnumProducts()枚举所有已安装的产品,MsiEnumerRelatedProducts()枚举给定升级代码的所有产品。但我找不到一个函数来获取系统中的所有升级代码。

我可以想象的解决方法是使用MsiEnumProducts()获取所有已安装产品的列表,用MsiOpenProduct()函数打开每个产品,并用MsiGetProductProperty()读取"UpgradeCode"属性。但是,由于有多个MsiOpenProduct()调用,这应该非常缓慢。

我相信MsiEnumProducts循环与MsiOpenProduct和MsiGetProductProperty是正确的官方顺序。如果你真的需要更快,并且愿意绕过API,你可以直接在HKCR\Installer\UpgradeCodes上阅读注册表。不过,你必须颠倒达尔文描述符。这在技术上不受支持,但事实是,这些密钥已经存在了16年,MSFT一直在Windows Installer上进行零开发。好吧,也许他们更新了版本号,并删除了Windows 10 LOL中的ARM支持。

FWIW,我喜欢使用C#而不是C++,但概念是一样的。下面的代码段在我的开发人员机器上运行了大约2秒钟。

using System;
using Microsoft.Deployment.WindowsInstaller;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (var productInstallation in ProductInstallation.AllProducts)
            {
                using(var database = new Database(productInstallation.LocalPackage, DatabaseOpenMode.ReadOnly))
                {
                    Console.WriteLine(database.ExecutePropertyQuery("UpgradeCode"));
                }
            }
        }
    }
}

根据DTF文档,ProductInstallation.AllProducts使用MsiEnumProducts。Database类构造函数使用MsiOpenDatabase,而ExecutePropertyQuery是一个更高级别的调用,它基本上是从属性WHERE属性="%s"抽象SELECT值。因此,它将调用API来创建、执行和从视图中获取结果。所有这些类都实现了IDisposable,以调用正确的API来释放资源。

耶。。。这就是我喜欢托管代码的原因。:)

最新更新