Alexey Semenyuk
Alexey Semenyuk

Reputation: 704

Enumerate Upgrade Codes of installed products?

I'd like to get list of all Upgrade codes of all installed products on Windows box. The question is: is there a dedicated MSI function to address this request?

There is MsiEnumProducts() that enumerates all installed products and MsiEnumRelatedProducts() to enumerate all products for the given Upgrade code. But I can't find a function to get all Upgrade codes in the system.

The workaround I can imagine is use MsiEnumProducts() to get list of all installed products, open each with MsiOpenProduct() function and read "UpgradeCode" property with MsiGetProductProperty(). But this should be very slow due to multiple MsiOpenProduct() calls.

Upvotes: 0

Views: 832

Answers (1)

Christopher Painter
Christopher Painter

Reputation: 55581

I believe MsiEnumProducts loop with MsiOpenProduct and then MsiGetProductProperty is the correct official sequence. If you really need faster and are willing to bypass the API's you could read the registry directly at HKCR\Installer\UpgradeCodes. You'll have to reverse the Darwin Descriptors though. This isn't technically supported but the reality is these keys have been there for 16 years and MSFT has been doing ZERO development on The Windows Installer. Ok, maybe they updated the version number and removed ARM support in Windows 10 LOL.

FWIW, I like to use C# not C++ but the concept is the same. The following snippet ran on my developer machine in about 2 seconds.

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

According to the DTF documentation, ProductInstallation.AllProducts uses MsiEnumProducts. The Database class constructor is using MsiOpenDatabase and ExecutePropertyQuery is a higher level call that basically abstracts doing a SELECT Value from Property WHERE Property = '%s'. So it'll be calling APIs to create, execute and fetch results from views. All these classes implement IDisposable to call the correct APIs to free resources also.

Ya... that's why I love managed code. :)

Upvotes: 2

Related Questions