15

WIX Toolsetの Windows Installer API の C# ラッパーを使用しています。このクラスを使用しProductInstallationて、製品コードや製品名など、インストールされている製品に関する情報を取得します。

例えば

  • 製品名 - 「My Test Application」
  • 商品コード - {F46BA620-C027-4E68-9069-5D5D4E1FF30A}
  • 製品バージョン - 1.4.0

内部的に、このラッパーはMsiGetProductInfo関数を使用します。残念ながら、この関数は製品のアップグレード コードを返しません。

C# を使用して、インストール済みアプリケーションのアップグレード コードを取得するにはどうすればよいですか?

4

6 に答える 6

40

アップグレード コードが次のレジストリの場所に保存されていることを発見しました。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes

レジストリ キーの名前はアップグレード コードで、レジストリ キーの値の名前は製品コードです。これらの値は簡単に抽出できますが、コードは別の形式で保存されています。赤い円はフォーマットされたアップグレード コードを示し、青い円は で表示したときにフォーマットされた製品コードを示しますregedit.exe

赤い丸はフォーマットされたアップグレード コード、青い丸はフォーマットされた製品コードです。

ハイフンが から取り除かれGuid、一連の文字列反転が行われます。最初の 8 文字が反転され、次の 4 文字、次の 4 文字、残りの文字列が 2 文字ずつ反転されます。通常、文字列を反転するときは、制御文字と特殊文字が正しく処理されるように注意する必要があります ( Jon Skeet の記事はこちらを参照)。Guid.

以下は、レジストリから既知の製品コードのアップグレード コードを抽出するために使用した完全なコードです。

internal static class RegistryHelper
{
    private const string UpgradeCodeRegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes";

    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();
    }
}
于 2013-07-29T23:43:04.810 に答える
5

InstallPackage クラスには、LocalPackage というプロパティがあります。これを使用して、C:\Windows\Installer にキャッシュされている MSI データベースにクエリを実行し、それについて知りたいと思われる情報を取得できます。

于 2013-07-30T01:43:22.427 に答える