通過維克斯標準引導程序應用的源尋找,似乎每個包具有DisplayName的屬性:獲取顯示名稱從包ID
pPackage->sczDisplayName
然而,在維克斯安裝中使用的BootstrapperCore DLL項目沒有這個屬性。有什麼辦法從託管代碼中的捆綁中提取此屬性?
通過維克斯標準引導程序應用的源尋找,似乎每個包具有DisplayName的屬性:獲取顯示名稱從包ID
pPackage->sczDisplayName
然而,在維克斯安裝中使用的BootstrapperCore DLL項目沒有這個屬性。有什麼辦法從託管代碼中的捆綁中提取此屬性?
我移植了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;
}
}
構建過程中生成的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
中看到代碼。
感謝這個信息。我們可以查詢這個來獲取顯示名稱,因爲我們已經在不同的事件/方法中提供了PackageId。 –
但是你不覺得顯示名稱或應用程序名稱應該像PackageId,ProductCode等一樣可用嗎? –
我們將引擎和BootstrapperApplication之間的接口保持爲儘可能最小,因爲它定義了一個隨時添加/刪除/更改它的合約。應用程序數據清單不是一個接口合約,所以我們可以根據需要進行增長。換言之,接口具有**必需的**數據來查找所有其他數據。 –
這工作完美。非常感謝! –