2012-10-11 5 views
9

Blick durch die Quelle der Anwendung Wix Standard-Bootstrapper, scheint es, dass jedes Paket eine Display Eigenschaft hat:Ersten Anzeigenamen von PackageID

pPackage->sczDisplayName 

jedoch die BootstrapperCore DLL, die in dem WiX-Setup verwendet wird, Projekt hat diese Eigenschaft nicht. Gibt es eine Möglichkeit, diese Eigenschaft aus den Bundles in verwaltetem Code zu extrahieren?

Antwort

11

ich portierte den Bal Code in C#, versuchte, es genau wie der C++ Code zu machen arbeiten:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Reflection; 
using System.Xml; 
using System.Xml.XPath; 

public class BootstrapperApplicationData 
{ 
    public const string defaultFileName = "BootstrapperApplicationData.xml"; 
    public const string xmlNamespace = 
     "http://schemas.microsoft.com/wix/2010/BootstrapperApplicationData"; 

    private static DirectoryInfo defaultFolder; 
    public static DirectoryInfo DefaultFolder 
    { 
     get 
     { 
      if (defaultFolder == null) 
      { 
       defaultFolder = (new FileInfo(Assembly.GetExecutingAssembly().Location)).Directory; 
      } 
      return defaultFolder; 
     } 
    } 

    private static FileInfo defaultFile; 
    public static FileInfo DefaultFile 
    { 
     get 
     { 
      if (defaultFile == null) 
      { 
       defaultFile = new FileInfo(Path.Combine(DefaultFolder.FullName, defaultFileName)); 
      } 
      return defaultFile; 
     } 
    } 

    public FileInfo DataFile { get; protected set; } 
    public Bundle Data { get; protected set; } 

    public BootstrapperApplicationData() : this(DefaultFile) { } 

    public BootstrapperApplicationData(FileInfo fiBootstrapperApplicationData) 
    { 
     DataFile = fiBootstrapperApplicationData; 
     using (FileStream fs = DataFile.OpenRead()) 
     { 
      Data = ParseBundleFromStream(fs); 
     } 
    } 

    public static Bundle ParseBundleFromStream(Stream stream) 
    { 
     XPathDocument manifest = new XPathDocument(stream); 
     XPathNavigator root = manifest.CreateNavigator(); 
     return ParseBundleFromXml(root); 
    } 

    public static Bundle ParseBundleFromXml(XPathNavigator root) 
    { 
     Bundle bundle = new Bundle(); 

     XmlNamespaceManager namespaceManager = new XmlNamespaceManager(root.NameTable); 
     namespaceManager.AddNamespace("p", xmlNamespace); 
     XPathNavigator bundleNode = root.SelectSingleNode("/p:BootstrapperApplicationData/p:WixBundleProperties", namespaceManager); 

     if (bundleNode == null) 
     { 
      throw new Exception("Failed to select bundle information"); 
     } 

     bool? perMachine = GetYesNoAttribute(bundleNode, "PerMachine"); 
     if (perMachine.HasValue) 
     { 
      bundle.PerMachine = perMachine.Value; 
     } 

     string name = GetAttribute(bundleNode, "DisplayName"); 
     if (name != null) 
     { 
      bundle.Name = name; 
     } 

     string logVariable = GetAttribute(bundleNode, "LogPathVariable"); 
     if (logVariable != null) 
     { 
      bundle.LogVariable = logVariable; 
     } 
     else 
     { 
      //wix would actually debug "Failed to select bundle information" and return with E_NOTFOUND, but I think it's a (harmless) bug 
     } 

     Package[] packages = ParsePackagesFromXml(root); 
     bundle.Packages = packages; 

     return bundle; 
    } 

    public static Package[] ParsePackagesFromXml(XPathNavigator root) 
    { 
     List<Package> packages = new List<Package>(); 

     XmlNamespaceManager namespaceManager = new XmlNamespaceManager(root.NameTable); 
     namespaceManager.AddNamespace("p", xmlNamespace); 
     XPathNodeIterator nodes = root.Select("/p:BootstrapperApplicationData/p:WixPackageProperties", namespaceManager); 

     foreach (XPathNavigator node in nodes) 
     { 
      Package package = new Package(); 

      string id = GetAttribute(node, "Package"); 
      if (id == null) 
      { 
       throw new Exception("Failed to get package identifier for package"); 
      } 
      package.Id = id; 

      string displayName = GetAttribute(node, "DisplayName"); 
      if (displayName != null) 
      { 
       package.DisplayName = displayName; 
      } 

      string description = GetAttribute(node, "Description"); 
      if (description != null) 
      { 
       package.Description = description; 
      } 

      PackageType? packageType = GetPackageTypeAttribute(node, "PackageType"); 
      if (!packageType.HasValue) 
      { 
       throw new Exception("Failed to get package type for package"); 
      } 
      package.Type = packageType.Value; 

      bool? permanent = GetYesNoAttribute(node, "Permanent"); 
      if (!permanent.HasValue) 
      { 
       throw new Exception("Failed to get permanent settings for package"); 
      } 
      package.Permanent = permanent.Value; 

      bool? vital = GetYesNoAttribute(node, "Vital"); 
      if (!vital.HasValue) 
      { 
       throw new Exception("Failed to get vital setting for package"); 
      } 
      package.Vital = vital.Value; 

      bool? displayInternalUI = GetYesNoAttribute(node, "DisplayInternalUI"); 
      if (!displayInternalUI.HasValue) 
      { 
       throw new Exception("Failed to get DisplayInternalUI setting for package"); 
      } 
      package.DisplayInternalUI = displayInternalUI.Value; 

      string productCode = GetAttribute(node, "ProductCode"); 
      if (productCode != null) 
      { 
       package.ProductCode = productCode; 
      } 

      string upgradeCode = GetAttribute(node, "UpgradeCode"); 
      if (upgradeCode != null) 
      { 
       package.UpgradeCode = upgradeCode; 
      } 

      string version = GetAttribute(node, "Version"); 
      if (version != null) 
      { 
       package.Version = version; 
      } 

      packages.Add(package); 
     } 

     return packages.ToArray(); 
    } 

    public static string GetAttribute(XPathNavigator node, string attributeName) 
    { 
     XPathNavigator attribute = node.SelectSingleNode("@" + attributeName); 

     if (attribute == null) 
     { 
      return null; 
     } 

     return attribute.Value; 
    } 

    public static bool? GetYesNoAttribute(XPathNavigator node, string attributeName) 
    { 
     string attributeValue = GetAttribute(node, attributeName); 

     if (attributeValue == null) 
     { 
      return null; 
     } 

     return attributeValue.Equals("yes", StringComparison.InvariantCulture); 
    } 

    public static PackageType? GetPackageTypeAttribute(XPathNavigator node, string attributeName) 
    { 
     string attributeValue = GetAttribute(node, attributeName); 

     if (attributeValue == null) 
     { 
      return null; 
     } 

     if (attributeValue.Equals("Exe", StringComparison.InvariantCulture)) 
     { 
      return PackageType.EXE; 
     } 
     else if (attributeValue.Equals("Msi", StringComparison.InvariantCulture)) 
     { 
      return PackageType.MSI; 
     } 
     else if (attributeValue.Equals("Msp", StringComparison.InvariantCulture)) 
     { 
      return PackageType.MSP; 
     } 
     else if (attributeValue.Equals("Msu", StringComparison.InvariantCulture)) 
     { 
      return PackageType.MSU; 
     } 
     else 
     { 
      return 0; 
     } 
    } 

    public enum PackageType 
    { 
     EXE, 
     MSI, 
     MSP, 
     MSU, 
    } 

    public class Package 
    { 
     public string Id; 
     public string DisplayName; 
     public string Description; 
     public PackageType Type; 
     public bool Permanent; 
     public bool Vital; 
     public bool DisplayInternalUI; 

     //not available until WiX 3.9.421.0 
     public string ProductCode; 
     public string UpgradeCode; 
     public string Version; 
    } 

    public class Bundle 
    { 
     public bool PerMachine; 
     public string Name; 
     public string LogVariable; 
     public Package[] Packages; 
    } 
} 
+0

Das funktioniert perfekt. Danke vielmals! –

5

Die Datei BootstrapperApplicationData.xml, die während des Erstellungsprozesses generiert wird, befindet sich neben Ihrer BA-DLL. Sie können diese XML-Datei laden, um viele Informationen über das Bundle und die Pakete im Bundle zu erhalten.

Um den BootstrapperApplicationData.xml in systemeigenem Code zu laden, verwenden Sie die BalManifestLoad()-Methode in balutil.lib, die mit dem WiX-Toolset bereitgestellt wird. Sie können den Code in src\ext\BalExtension\balutil\balutil.cpp sehen. Dann können Sie BalInfoParseFromXml() auch in balutil.lib verwenden, um die XML-Datei in eine Reihe von handlichen Strukturen zu analysieren. Sie können den Code in src\ext\BalExtension\balutil\balinfo.cpp sehen.

+0

Vielen Dank für diese Informationen. Wir können dies abfragen, um den Anzeigenamen zu erhalten, da wir PackageId bereits in verschiedenen Ereignissen/Methoden verfügbar haben. –

+1

Aber denken Sie nicht, Anzeigename oder Anwendungsname sollte wie PackageId, ProductCode usw. verfügbar sein? –

+1

Wir halten die Schnittstelle zwischen der Engine und BootstrapperApplication so minimal wie möglich, da dies einen Vertrag definiert, der bricht, wenn wir hinzufügen/entfernen/ändern. Das Anwendungsdatenmanifest ist kein Schnittstellenvertrag, sodass wir bei Bedarf wachsen können. Anders gesagt, die Schnittstelle hat die ** notwendigen ** Daten, um alle anderen Daten zu finden. –