| File: Msi\WixDocument.cs | Web Access |
| Project: src\arcade\src\Microsoft.DotNet.Build.Tasks.Workloads\src\Microsoft.DotNet.Build.Tasks.Workloads.csproj (Microsoft.DotNet.Build.Tasks.Workloads) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Linq; using System.Xml.Linq; namespace Microsoft.DotNet.Build.Tasks.Workloads.Msi { /// <summary> /// Class for loading and modifying existing WiX XML source files to support compositional authoring. /// </summary> public class WixDocument { private static readonly XNamespace s_wixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; private XDocument _doc; private string _path; public static string GetDirectoryReference() => $"dir{Guid.NewGuid():N}"; public XElement Package => _doc.Root.Descendants(s_wixNamespace + "Package").FirstOrDefault(); /// <summary> /// Creates a new instance of the <see cref="WixDocument"/> class by loading an existing WiX XML /// document from the specified file path. /// </summary> /// <param name="path">The path of the WiX XML document.</param> public WixDocument(string path) { _doc = XDocument.Load(path); _path = path; } /// <summary> /// Save the current current state of the WiX XML document to the orignal file path. /// </summary> public void Save() { _doc.Save(_path); } /// <summary> /// Gets the first Directory element with matching Id attribute. /// </summary> /// <param name="id">The directory identifier to match.</param> /// <returns>The first matching Directory element or null if no elements exist.</returns> public XElement GetDirectory(string id) => GetElement("Directory", id); /// <summary> /// Searches the underlying document for the first element matching the provided name and ID. /// </summary> /// <param name="elementName">The name of the element to find.</param> /// <param name="id">The Id attribute of the element to match. If null, the first matching element is returned.</param> /// <param name="ns">Optional namespace to use. If null, the default WiX namespace is used.</param> /// <returns>The element or null if it was not found.</returns> public XElement GetElement(string elementName, string id = null, XNamespace ns = null) { if (string.IsNullOrWhiteSpace(id)) { return _doc.Root.Descendants((ns ?? s_wixNamespace) + elementName).FirstOrDefault(); } foreach (XElement element in _doc.Root.Descendants((ns ?? s_wixNamespace) + elementName)) { if (element.Attribute("Id")?.Value == id) { return element; } } return null; } /// <summary> /// Gets the first Feature element with matching Id attribute. /// </summary> /// <param name="id">The feature identifier to match</param> /// <returns>The Feature element or null if it does not exist.</returns> public XElement GetFeature(string id) => GetElement("Feature", id); /// <summary> /// Adds a RegistryKey element to the specified component. /// </summary> /// <param name="componentId">The identifier of the component.</param> /// <param name="registryKey">The RegistryKey element to add.</param> /// <exception cref="InvalidOperationException" /> public void AddRegistryKey(string componentId, XElement registryKey) { var component = GetElement("Component", componentId) ?? throw new InvalidOperationException($"The specified component does not exist: {componentId}"); component.Add(registryKey); } /// <summary> /// Adds a Property element to the Package. /// </summary> /// <param name="id">The property identifier.</param> /// <param name="value"></param> public void AddProperty(string id, string value) => Package.Add(new XElement(s_wixNamespace + "Property", new XAttribute("Id", id), new XAttribute("Value", value))); /// <summary> /// Adds a PropertyRef element to the Package. /// </summary> /// <param name="id"></param> public void AddPropertyRef(string id) => Package.Add(new XElement(s_wixNamespace + "PropertyRef", new XAttribute("Id", id))); /// <summary> /// Adds a CustomActionRef element to the Package. /// </summary> /// <param name="id"></param> public void AddCustomActionRef(string id) => Package.Add(new XElement(s_wixNamespace + "CustomActionRef", new XAttribute("Id", id))); /// <summary> /// Creates a directory element with the provided name and unique identifier. /// </summary> /// <param name="name">The name of the directory.</param> /// <returns>A new element representing the directory.</returns> public static XElement CreateDirectory(string name) => CreateDirectory(name, $"dir{Guid.NewGuid():N}"); /// <summary> /// Creates a directory element with the provided name and identifier. /// </summary> /// <param name="name">The name of the directory.</param> /// <param name="id">The identifier for the directory element. The identifier must be unique within the installer.</param> /// <returns>A new element representing the directory.</returns> public static XElement CreateDirectory(string name, string id) => new XElement(s_wixNamespace + "Directory", new XAttribute("Id", id), new XAttribute("Name", name)); /// <summary> /// Creates a RegistryKey element with the specified key path and root hive. The new element can be added as a child to any existing Component or RegistryKey element. /// </summary> /// <param name="key">The name of the registry key.</param> /// <param name="root">The registry key (HKLM, HKCR, etc.).</param> /// <returns></returns> public static XElement CreateRegistryKey(string key, string root = "HKLM") => new XElement(s_wixNamespace + "RegistryKey", new XAttribute("Root", root), new XAttribute("Key", key)); } }