2012-10-11 119 views
9

通過維克斯標準引導程序應用的源尋找,似乎每個包具有DisplayName的屬性:獲取顯示名稱從包ID

pPackage->sczDisplayName 

然而,在維克斯安裝中使用的BootstrapperCore DLL項目沒有這個屬性。有什麼辦法從託管代碼中的捆綁中提取此屬性?

回答

11

我移植了Bal代碼轉換成C#,試圖使其工作完全一樣的C++代碼:

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

這工作完美。非常感謝! –

5

構建過程中生成的BootstrapperApplicationData.xml文件放在您的BA .dll旁邊。您可以加載該XML文件以獲取有關捆綁軟件包和軟件包的大量信息。

要使用本機代碼加載BootstrapperApplicationData.xml,請使用隨WiX工具集提供的balutil.lib中的BalManifestLoad()方法。您可以在src\ext\BalExtension\balutil\balutil.cpp中看到代碼。然後,您也可以在balutil.lib中使用BalInfoParseFromXml()將XML文件解析爲一堆方便的結構。您可以在src\ext\BalExtension\balutil\balinfo.cpp中看到代碼。

+0

感謝這個信息。我們可以查詢這個來獲取顯示名稱,因爲我們已經在不同的事件/方法中提供了PackageId。 –

+1

但是你不覺得顯示名稱或應用程序名稱應該像PackageId,ProductCode等一樣可用嗎? –

+1

我們將引擎和BootstrapperApplication之間的接口保持爲儘可能最小,因爲它定義了一個隨時添加/刪除/更改它的合約。應用程序數據清單不是一個接口合約,所以我們可以根據需要進行增長。換言之,接口具有**必需的**數據來查找所有其他數據。 –