Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
491 views
in Technique[技术] by (71.8m points)

wix - How can I find the upgrade code for an installed application in C#?

I am using the C# wrapper for the Windows Installer API from the WIX Toolset. I use the ProductInstallation class to get information about the installed products such as the product code and product name.

For example

  • Product Name - "My Test Application"
  • Product Code - {F46BA620-C027-4E68-9069-5D5D4E1FF30A}
  • Product Version - 1.4.0

Internally this wrapper uses the MsiGetProductInfo function. Unfortunately this function does not return the product's upgrade code.

How can I retrieve the upgrade code for an installed application using C#?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I have discovered the upgrade codes are stored in the following registry location.

HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionInstallerUpgradeCodes

The registry key name is the upgrade code and the registry key value name is the product code. I can easily extract these values however the codes are stored in a different format. The red circle shows the formatted upgrade code, the blue circle shows the formatted product code when viewing it in regedit.exe.

Red circle is the formatted upgrade code, the blue circle the formatted product code

The hyphens are stripped out of the Guid and then a series of string reversals are done. The first 8 characters are reversed, then the next 4, then the following 4 and then the rest of the string is reversed in sets of 2 characters. Normally when reversing a string we need to take care in making sure control and special characters are handled correctly (see Jon Skeet's aricle here) but as we are, in this case, dealing with a Guid string we can be confident the string will be reversed correctly.

Below is the complete code I used to extract the upgrade code for a known product code from the registry.

internal static class RegistryHelper
{
    private const string UpgradeCodeRegistryKey = @"SOFTWAREMicrosoftWindowsCurrentVersionInstallerUpgradeCodes";


    private static readonly int[] GuidRegistryFormatPattern = new[] { 8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2 };

    public static Guid? GetUpgradeCode(Guid productCode)
    {
        // Convert the product code to the format found in the registry
        var productCodeSearchString = ConvertToRegistryFormat(productCode);

        // Open the upgrade code registry key
        var localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
        var upgradeCodeRegistryRoot = localMachine.OpenSubKey(UpgradeCodeRegistryKey);

        if (upgradeCodeRegistryRoot == null)
            return null;

        // Iterate over each sub-key
        foreach (var subKeyName in upgradeCodeRegistryRoot.GetSubKeyNames())
        {
            var subkey = upgradeCodeRegistryRoot.OpenSubKey(subKeyName);

            if (subkey == null)
                continue;

            // Check for a value containing the product code
            if (subkey.GetValueNames().Any(s => s.IndexOf(productCodeSearchString, StringComparison.OrdinalIgnoreCase) >= 0))
            {
                // Extract the name of the subkey from the qualified name
                var formattedUpgradeCode = subkey.Name.Split('\').LastOrDefault();

                // Convert it back to a Guid
                return ConvertFromRegistryFormat(formattedUpgradeCode);
            }
        }

        return null;
    }

    private static string ConvertToRegistryFormat(Guid productCode)
    {
        return Reverse(productCode, GuidRegistryFormatPattern);
    }

    private static Guid ConvertFromRegistryFormat(string upgradeCode)
    {
        if (upgradeCode == null || upgradeCode.Length != 32)
            throw new FormatException("Product code was in an invalid format");

        upgradeCode = Reverse(upgradeCode, GuidRegistryFormatPattern);

        return Guid.Parse(upgradeCode);
    }

    private static string Reverse(object value, params int[] pattern)
    {
        // Strip the hyphens
        var inputString = value.ToString().Replace("-", "");

        var returnString = new StringBuilder();

        var index = 0;

        // Iterate over the reversal pattern
        foreach (var length in pattern)
        {
            // Reverse the sub-string and append it
            returnString.Append(inputString.Substring(index, length).Reverse().ToArray());

            // Increment our posistion in the string
            index += length;
        }

        return returnString.ToString();
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...