2013-07-29 14 views
10

Windows Installer API'sı için C# sarmalayıcısını WIX Toolset'dan kullanıyorum. Ürün kodu ve ürün adı gibi yüklü ürünler hakkında bilgi almak için ProductInstallation sınıfını kullanıyorum. ÖrneğinYüklü bir uygulama için yükseltme kodunu C# içinde nasıl bulabilirim?

  • Ürün Adı İçin

    - "Benim Testi Uygulaması"

  • Ürün Kodu - {F46BA620-C027-4E68-9069-5D5D4E1FF30A}
  • Ürün Sürüm - 1.4.0

Dahili olarak bu sarıcı, MsiGetProductInfo işlevini kullanır. Maalesef bu işlev ürünün yükseltme kodunu döndürmez.

Yüklü bir uygulama için yükseltme kodunu C# kullanarak nasıl edinebilirim?

+0

yerine kayıt kullanarak, ** Bu cevap açıklandığı gibi WMı'ni kullanmanızı öneriyoruz **: [** Ben nasıl Yüklü bir MSI dosyası için Yükseltme Kodunu bulmak? **] (https: // stackoverflow.com/sorular/46637094/how-can-ı-bulmak-yükseltme-kod-için-bir-yüklü-msi-dosya/46637095 # 46637095). Bu, doğru yükseltme kodunu almanızı sağlayacak ve herhangi bir dönüşüm veya yorum gerektirmeyecektir. ** Gerçek yükseltme kodunu uygun formatta ** alacaksınız. –

cevap

22

Yükseltme kodlarının aşağıdaki kayıt defteri konumunda saklandığını keşfettim.

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

Kayıt defteri anahtarı adı, yükseltme kodudur ve kayıt defteri anahtarı değeri adı, ürün kodudur. Bu değerleri kolaylıkla çıkarabilirim ancak kodlar farklı bir biçimde saklanır. Kırmızı daire biçimlendirilmiş yükseltme kodunu gösterir, mavi daire regedit.exe'da görüntülendiğinde biçimlendirilmiş ürün kodunu gösterir.

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

tire Guid dışına soyulur ve sonra dize tersine dönmesinin bir dizi yapılır. İlk 8 karakter tersine çevrilir, ardından sonraki 4, sonra aşağıdaki 4 ve daha sonra dizenin geri kalanı 2 karakter kümesinde tersine çevrilir. Normalde, bir dizgiyi tersine çevirirken, kontrolün ve özel karakterlerin doğru bir şekilde (see Jon Skeet's aricle here) ele alınmasına dikkat etmemiz gerekir, ancak bu durumda, bir Guid dizgisiyle ilgili olarak, dizgenin doğru bir şekilde tersine çevrileceğinden emin olabiliriz.

Kayıttan bilinen bir ürün kodu için yükseltme kodunu ayıklamak için kullandığım kodun tamamı aşağıdadır.

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(); 
    } 
} 
+0

Yukarıdaki programda, ilgili ürün kodu için NULL döndürüyor. Her yükseltme kodu, ürün koduyla girişini yapar mı? Ürün kodumdan etiketleri kaldırdım ancak tire (-) değil. Hala çalışmıyor. – Keshav

+0

Hata Ayıklama İşlemi Yaptıktan sonra, kayıt defterinin mevcut konumda olduğunu öğrendim ancak upgradeCodeRegistryRoot NULL değer alıyor – Keshav

+0

"Kayıt defteri anahtarı adı, yükseltme kodu" yanlıştır! Kayıt defteri anahtarları yükseltme kodlarına eşit değildir! –

4

InstallPackage sınıfının LocalPackage adlı bir özelliği vardır. Bunu, C: \ Windows \ Installer'da önbelleğe alınan MSI veritabanını sorgulamak ve bunun hakkında bilmek isteyebileceğiniz bir şey almak için kullanabilirsiniz.

+0

Evet, bu doğru ama güvenilir değil. MSI paketi hala orada olduğu sürece sadece yararlıdır. Birkaç PC'deki hızlı bir test sırasında MSI'ın bulunmamasının oldukça yaygın olduğunu buldum (test edilen 593 paketin% 27'sinde veya% 5'inde eksik). Bu testlerde, tüm yükseltme kodları hala kayıttan temin edilmiştir. –

+1

Bu MSI'lar her zaman orada olmalı, aksi takdirde onarım, kaldırma, reklamı yapılan kısayollar vb. Ile ilgili sorunlarınız olacaktır. http://blogs.msdn.com/b/sqlserverfaq/archive/2013/04/30/do-not-delete-files-from-the-windows-installer-folder.aspx –

+0

Kabul ediyorum; Onlar orada olmalılar. Ne yazık ki bazen değiller. Bunun, istemci bilgisayarlara yüklenecek bir envanter tarzı hizmet için olduğunu ve daha güvenilir bir yönteme ihtiyaç duyduğumu açıklamalıyım. –

1

Bu, UpCodeCode'dan ProductCode'u almak için tersi yöntemdir. Birisi için yararlı olabilir.

using Microsoft.Win32; 
using System; 
using System.IO; 
using System.Linq; 
using System.Text; 

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? GetProductCode(Guid upgradeCode) 
    { 
     // Convert the product code to the format found in the registry 
     var productCodeSearchString = ConvertToRegistryFormat(upgradeCode); 

     // Open the upgrade code registry key 
     var upgradeCodeRegistryRoot = GetRegistryKey(Path.Combine(UpgradeCodeRegistryKey, productCodeSearchString)); 

     if (upgradeCodeRegistryRoot == null) 
      return null; 

     var uninstallCode = upgradeCodeRegistryRoot.GetValueNames().FirstOrDefault(); 
     if (string.IsNullOrEmpty(uninstallCode)) 
     { 
      return null; 
     } 

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





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

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

     code = Reverse(code, GuidRegistryFormatPattern); 

     return Guid.Parse(code); 
    } 

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

    static RegistryKey GetRegistryKey(string registryPath) 
    { 
     var hklm64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); 
     var registryKey64 = hklm64.OpenSubKey(registryPath); 
     if (((bool?)registryKey64?.GetValueNames()?.Any()).GetValueOrDefault()) 
     { 
      return registryKey64; 
     } 

     var hklm32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32); 
     return hklm32.OpenSubKey(registryPath); 
    } 
} 
+2

@Alex Wiese kodu benim için iyi çalışıyor. Bu kod yok. Bununla birlikte, belirli bir UpgradeCode için ProductCode'u bularak zıt aramayı gerçekleştirir. – harlam357

+0

@ harlam357 Yorumlarınız için teşekkür ederiz. Haklısın. Cevabı kabul edilen cevabı tamamlamak için güncelledim. –

0

Ve burada sizin yardımcınız .Net3.5 32 bit uygulamalarda da çalışacak şekilde değiştirilmiştir. Özel bir tedaviye ihtiyaçları var çünkü .net 3.5, kayıt defterinin 32 ve 64 bit girişler arasında bölünmesiyle ilgili hiçbir farkındalığa sahip değil. Benim çözümüm sadece 64 bit parçasına göz atmak için To64BitPath kullanıyor. büyük olduğu için DllImports kullanır öğretici da vardır: Aşağıdaki önerildiği gibi https://www.rhyous.com/2011/01/24/how-read-the-64-bit-registry-from-a-32-bit-application-or-vice-versa/

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

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



    public static string To64BitPath(string path) 
    { 
     return path.Replace("SOFTWARE\\Microsoft", "SOFTWARE\\WOW6432Node\\Microsoft"); 
    } 

    private static RegistryKey GetLocalMachineRegistryKey(string path) 
    { 
     return RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty).OpenSubKey(path); 
    } 

    public static IEnumerable<Guid> GetUpgradeCodes() 
    { 
     var list = new List<Guid>(); 

     var key = GetRegistryKey(UpgradeCodeRegistryKey); 
     if (key != null) 
     { 
      list.AddRange(key.GetSubKeyNames().Select(ConvertFromRegistryFormat)); 
     } 

     return list; 
    } 

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

     // Open the upgradeCode upgradeCode registry key 
     var upgradeCodeRegistryRoot = GetRegistryKey(Path.Combine(UpgradeCodeRegistryKey, productCodeSearchString)); 

     if (upgradeCodeRegistryRoot == null) 
      return null; 

     var uninstallCode = upgradeCodeRegistryRoot.GetValueNames().FirstOrDefault(); 
     if (string.IsNullOrEmpty(uninstallCode)) 
     { 
      return null; 
     } 

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

    public static string ConvertToRegistryFormat(Guid code) 
    { 
     return Reverse(code, GuidRegistryFormatPattern); 
    } 

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

     code = Reverse(code, GuidRegistryFormatPattern); 

     return new Guid(code); 
    } 

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

    static RegistryKey GetRegistryKey(string registryPath) 
    { 
     var registryKey64 = GetLocalMachineRegistryKey(To64BitPath(registryPath)); 
     if (((bool?)registryKey64?.GetValueNames()?.Any()).GetValueOrDefault()) 
     { 
      return registryKey64; 
     } 

     return GetLocalMachineRegistryKey(registryPath); 
    } 


    public static Guid? GetUpgradeCode(Guid productCode) 
    { 
     var productCodeSearchString = ConvertToRegistryFormat(productCode); 
     var upgradeCodeRegistryRoot = GetRegistryKey(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 upgradeCode 
      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; 
    } 
} 
İlgili konular