From 72f3dceefa2e3893b061e074380794bc60b67b6f Mon Sep 17 00:00:00 2001
From: Sean Hall <r.sean.hall@gmail.com>
Date: Sun, 3 Feb 2019 13:20:43 -0600
Subject: Import code from old v4 repo

---
 src/wixext/Dependency.xsd             | 226 +++++++++++++
 src/wixext/DependencyBinder.cs        | 169 ++++++++++
 src/wixext/DependencyCommon.cs        |  26 ++
 src/wixext/DependencyCompiler.cs      | 615 ++++++++++++++++++++++++++++++++++
 src/wixext/DependencyDecompiler.cs    | 345 +++++++++++++++++++
 src/wixext/DependencyExtension.csproj |  50 +++
 src/wixext/DependencyExtensionData.cs |  64 ++++
 src/wixext/messages.xml               |  60 ++++
 src/wixext/tables.xml                 |  38 +++
 9 files changed, 1593 insertions(+)
 create mode 100644 src/wixext/Dependency.xsd
 create mode 100644 src/wixext/DependencyBinder.cs
 create mode 100644 src/wixext/DependencyCommon.cs
 create mode 100644 src/wixext/DependencyCompiler.cs
 create mode 100644 src/wixext/DependencyDecompiler.cs
 create mode 100644 src/wixext/DependencyExtension.csproj
 create mode 100644 src/wixext/DependencyExtensionData.cs
 create mode 100644 src/wixext/messages.xml
 create mode 100644 src/wixext/tables.xml

(limited to 'src/wixext')

diff --git a/src/wixext/Dependency.xsd b/src/wixext/Dependency.xsd
new file mode 100644
index 00000000..0c36cb88
--- /dev/null
+++ b/src/wixext/Dependency.xsd
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
+
+
+<xs:schema xmlns:html="http://www.w3.org/1999/xhtml"
+           xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns:xse=" http://wixtoolset.org/schemas/XmlSchemaExtension"
+           targetNamespace="http://wixtoolset.org/schemas/v4/wxs/dependency"
+           xmlns="http://wixtoolset.org/schemas/v4/wxs/dependency">
+    <xs:annotation>
+        <xs:documentation>
+            The source code schema for the WiX Toolset Dependency Extension.
+        </xs:documentation>
+    </xs:annotation>
+    <xs:element name="Provides">
+        <xs:annotation>
+            <xs:documentation>
+                Describes the information for this product or feature that serves as a dependency of other products or features.
+            </xs:documentation>
+            <xs:appinfo>
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Component" />
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="ExePackage" />
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="MsiPackage" />
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="MspPackage" />
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="MsuPackage" />
+                <xse:remarks>
+                    <html:p>
+                        This element is required for any product, feature, or bundle that will use the Dependency feature to properly reference count
+                        other products or features. It should be authored into a component that is always installed and removed with the
+                        product or features that contain it. This guarantees that product dependencies are not removed before those products that
+                        depend on them.
+                    </html:p>
+                    <html:p>
+                        The @Key attribute should identify a version range for your product that you guarantee will be backward compatible.
+                        This key is designed to persist throughout compatible upgrades so that dependent products do not have to be reinstalled
+                        and will not prevent your product from being upgraded. If this attribute is not authored, the value is the ProductCode
+                        and will not automatically support upgrades.
+                    </html:p>
+                    <html:p>
+                        By default this uses the Product/@Id attribute value, which may be automatically generated.
+                    </html:p>
+                </xse:remarks>
+                <xse:howtoRef href="author_product_dependencies.html">How To: Author product dependencies</xse:howtoRef>
+            </xs:appinfo>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element ref="Requires" />
+                <xs:element ref="RequiresRef" />
+            </xs:choice>
+            <xs:attribute name="Id" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation>
+                        Dependency provider identity. If this attribute is not specified, an identifier will be generated automatically.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="Key" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation>
+                        Optional unique registry key name that identifies a product version range on which other products can depend.
+                        This attribute is required in package authoring, but optional for components.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="Version" type="VersionType">
+                <xs:annotation>
+                    <xs:documentation>
+                        The version of the package. For MSI packages, the ProductVersion will be used by default
+                        and this attribute should not be specified.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="DisplayName" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation>
+                        Optional display name of the package. For MSI packages, the ProductName will be used by default.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="Requires">
+        <xs:annotation>
+            <xs:documentation>
+                Describes a dependency on a provider for the current component or package.
+            </xs:documentation>
+            <xs:appinfo>
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" />
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Fragment" />
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Module" />
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Product" />
+                <xse:remarks>
+                    <html:p>
+                        This element declares a dependency on any product that uses the Provides element. If that product is uninstalled
+                        before a product that requires it, the uninstall will err or warn the user that other products are installed
+                        which depend on that product. This behavior can be modified by changing the attribute values on the Requires element.
+                    </html:p>
+                    <html:p>
+                        If you do not nest this element under a Provides element, you must specify the @Id attribute
+                        so that it can be referenced by a RequiresRef element nested under a Provides element.
+                    </html:p>
+                </xse:remarks>
+                <xse:seeAlso ref="RequiresRef" />
+                <xse:howtoRef href="author_product_dependencies.html">How To: Author product dependencies</xse:howtoRef>
+            </xs:appinfo>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:attribute name="Id" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation>
+                        Dependency requirement identity. If this attribute is not specified, an identifier will be generated automatically.
+                        If this element is not authored under a Provides element, this attribute is required.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="ProviderKey" type="xs:string" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The unique registry key name for the dependency provider to require during installation of this product.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="Minimum" type="VersionType">
+                <xs:annotation>
+                    <xs:documentation>
+                        The minimum version of the dependency provider required to be installed. The default is unbound.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="Maximum" type="VersionType">
+                <xs:annotation>
+                    <xs:documentation>
+                        The maximum version of the dependency provider required to be installed. The default is unbound.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="IncludeMinimum" type="YesNoType">
+                <xs:annotation>
+                    <xs:documentation>
+                        Set to "yes" to make the range of dependency provider versions required include the value specified in Minimum.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="IncludeMaximum" type="YesNoType">
+                <xs:annotation>
+                    <xs:documentation>
+                        Set to "yes" to make the range of dependency provider versions required include the value specified in Maximum.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="RequiresRef">
+        <xs:annotation>
+            <xs:documentation>
+                References existing authoring for a dependency on a provider for the current component or package.
+            </xs:documentation>
+            <xs:appinfo>
+                <xse:remarks>
+                    <html:p>
+                        This element references a dependency on any product that uses the Provides element. If that product is uninstalled
+                        before a product that requires it, the uninstall will err or warn the user that other products are installed
+                        which depend on that product. This behavior can be modified by changing the attribute values on the Requires element.
+                    </html:p>
+                </xse:remarks>
+                <xse:seeAlso ref="Requires" />
+                <xse:howtoRef href="author_product_dependencies.html">How To: Author product dependencies</xse:howtoRef>
+            </xs:appinfo>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:attribute name="Id" type="xs:string" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The identifier of the Requires element to reference.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+    <xs:attribute name="ProviderKey" type="xs:string">
+        <xs:annotation>
+            <xs:documentation>
+                Optional attribute to explicitly author the provider key for the entire bundle.
+            </xs:documentation>
+            <xs:appinfo>
+                <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" />
+                <xse:remarks>
+                    <html:p>
+                        This provider key is designed to persist throughout compatible upgrades so that dependent bundles do not have to be reinstalled
+                        and will not prevent your product from being upgraded. If this attribute is not authored, the value is the
+                        automatically-generated bundle ID and will not automatically support upgrades.
+                    </html:p>
+                    <html:p>
+                        Only a single provider key is supported for bundles. To author that your bundle provides additional features via
+                        packages, author different provider keys for your packages.
+                    </html:p>
+                </xse:remarks>
+                <xse:seeAlso ref="Provides" />
+            </xs:appinfo>
+        </xs:annotation>
+    </xs:attribute>
+    <xs:simpleType name="VersionType">
+        <xs:annotation>
+            <xs:documentation>
+                Values of this type will look like: "x.x.x.x" where x is an integer from 0 to 65534.
+                This can also be a preprocessor, binder, or WiX variable.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="(\d{1,5}\.){3}\d{1,5}|[!$]\((var|bind|wix)\.[_A-Za-z][\w\.]*\)" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="YesNoType">
+        <xs:annotation>
+            <xs:documentation>
+                Values of this type will either be "yes" or "no".
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:NMTOKEN">
+            <xs:enumeration value="no" />
+            <xs:enumeration value="yes" />
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>
diff --git a/src/wixext/DependencyBinder.cs b/src/wixext/DependencyBinder.cs
new file mode 100644
index 00000000..13fea203
--- /dev/null
+++ b/src/wixext/DependencyBinder.cs
@@ -0,0 +1,169 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
+
+namespace WixToolset.Extensions
+{
+    using System;
+    using System.Collections.ObjectModel;
+    using System.Globalization;
+    using WixToolset.Data;
+    using WixToolset.Extensibility;
+
+    /// <summary>
+    /// The compiler for the WiX toolset dependency extension.
+    /// </summary>
+    public sealed class DependencyBinder : BinderExtension
+    {
+        private Output output;
+
+        /// <summary>
+        /// Called after all output changes occur and right before the output is bound into its final format.
+        /// </summary>
+        public override void Finish(Output output)
+        {
+            // Only process MSI packages.
+            if (OutputType.Product != output.Type)
+            {
+                return;
+            }
+
+            this.output = output;
+
+            Table wixDependencyTable = output.Tables["WixDependency"];
+            Table wixDependencyProviderTable = output.Tables["WixDependencyProvider"];
+            Table wixDependencyRefTable = output.Tables["WixDependencyRef"];
+
+            // Make sure there's something to do.
+            if (null != wixDependencyRefTable)
+            {
+                KeyedRowCollection wixDependencyRows = new KeyedRowCollection(wixDependencyTable);
+                KeyedRowCollection wixDependencyProviderRows = new KeyedRowCollection(wixDependencyProviderTable);
+
+                // For each relationship, get the provides and requires rows to generate registry values.
+                foreach (Row wixDependencyRefRow in wixDependencyRefTable.Rows)
+                {
+                    string providesId = (string)wixDependencyRefRow[0];
+                    string requiresId = (string)wixDependencyRefRow[1];
+
+                    Row wixDependencyRow = null;
+                    if (wixDependencyRows.Contains(requiresId))
+                    {
+                        wixDependencyRow = wixDependencyRows[requiresId];
+                    }
+
+                    Row wixDependencyProviderRow = null;
+                    if (wixDependencyProviderRows.Contains(providesId))
+                    {
+                        wixDependencyProviderRow = wixDependencyProviderRows[providesId];
+                    }
+
+                    // If we found both rows, generate the registry values.
+                    if (null != wixDependencyRow && null != wixDependencyProviderRow)
+                    {
+                        // Format the root registry key using the required provider key and the current provider key.
+                        string requiresKey = (string)wixDependencyRow[1];
+                        string providesKey = (string)wixDependencyProviderRow[2];
+                        string keyRequires = String.Format(@"{0}{1}\{2}\{3}", DependencyCommon.RegistryRoot, requiresKey, DependencyCommon.RegistryDependents, providesKey);
+
+                        // Get the component ID from the provider.
+                        string componentId = (string)wixDependencyProviderRow[1];
+
+                        Row row = this.CreateRegistryRow(wixDependencyRow);
+                        row[0] = this.Core.CreateIdentifier("reg", providesId, requiresId, "(Default)");
+                        row[1] = -1;
+                        row[2] = keyRequires;
+                        row[3] = "*";
+                        row[4] = null;
+                        row[5] = componentId;
+
+                        string minVersion = (string)wixDependencyRow[2];
+                        if (!String.IsNullOrEmpty(minVersion))
+                        {
+                            row = this.CreateRegistryRow(wixDependencyRow);
+                            row[0] = this.Core.CreateIdentifier("reg", providesId, requiresId, "MinVersion");
+                            row[1] = -1;
+                            row[2] = keyRequires;
+                            row[3] = "MinVersion";
+                            row[4] = minVersion;
+                            row[5] = componentId;
+                        }
+
+                        string maxVersion = (string)wixDependencyRow[3];
+                        if (!String.IsNullOrEmpty(minVersion))
+                        {
+                            row = this.CreateRegistryRow(wixDependencyRow);
+                            row[0] = this.Core.CreateIdentifier("reg", providesId, requiresId, "MaxVersion");
+                            row[1] = -1;
+                            row[2] = keyRequires;
+                            row[3] = "MaxVersion";
+                            row[4] = maxVersion;
+                            row[5] = componentId;
+                        }
+
+                        if (null != wixDependencyRow[4])
+                        {
+                            int attributes = (int)wixDependencyRow[4];
+
+                            row = this.CreateRegistryRow(wixDependencyRow);
+                            row[0] = this.Core.CreateIdentifier("reg", providesId, requiresId, "Attributes");
+                            row[1] = -1;
+                            row[2] = keyRequires;
+                            row[3] = "Attributes";
+                            row[4] = String.Concat("#", attributes.ToString(CultureInfo.InvariantCulture.NumberFormat));
+                            row[5] = componentId;
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Creates a registry row using source information from the given <see cref="Row"/>.
+        /// </summary>
+        /// <param name="referenceRow">The <see cref="Row"/> from which the section and source line information are retrieved.</param>
+        /// <returns>A new Registry row.</returns>
+        private Row CreateRegistryRow(Row referenceRow)
+        {
+            TableDefinition tableDefinition = this.Core.TableDefinitions["Registry"];
+
+            // Create the row from the main tables, which were populated during link anyway.
+            // We still associate the table with the dependency row's section to maintain servicing.
+            Table table = this.output.EnsureTable(tableDefinition, referenceRow.Table.Section);
+            Row row = table.CreateRow(referenceRow.SourceLineNumbers);
+            
+            // Set the section ID for patching and return the new row.
+            row.SectionId = referenceRow.SectionId;
+            return row;
+        }
+
+        /// <summary>
+        /// A keyed collection of <see cref="Row"/> instances for O(1) lookup.
+        /// </summary>
+        private sealed class KeyedRowCollection : KeyedCollection<string, Row>
+        {
+            /// <summary>
+            /// Initializes the <see cref="KeyedRowCollection"/> class with all rows from the specified <paramref name="table"/>.
+            /// </summary>
+            /// <param name="table">The <see cref="Table"/> containing rows to index.</param>
+            internal KeyedRowCollection(Table table)
+            {
+                if (null != table)
+                {
+                    foreach (Row row in table.Rows)
+                    {
+                        this.Add(row);
+                    }
+                }
+            }
+
+            /// <summary>
+            /// Gets the primary key for the <see cref="Row"/>.
+            /// </summary>
+            /// <param name="row">The <see cref="Row"/> to index.</param>
+            /// <returns>The primary key for the <see cref="Row"/>.</returns>
+            protected override string GetKeyForItem(Row row)
+            {
+                return row.GetPrimaryKey('/');
+            }
+        }
+    }
+}
diff --git a/src/wixext/DependencyCommon.cs b/src/wixext/DependencyCommon.cs
new file mode 100644
index 00000000..4826d8b0
--- /dev/null
+++ b/src/wixext/DependencyCommon.cs
@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
+
+namespace WixToolset.Extensions
+{
+    using System;
+    using WixToolset;
+
+    internal static class DependencyCommon
+    {
+        // Bundle attributes are in the upper 32-bits.
+        internal const int ProvidesAttributesBundle = 0x10000;
+
+        // Same values as for the Upgrade table in Windows Installer.
+        internal const int RequiresAttributesMinVersionInclusive = 256;
+        internal const int RequiresAttributesMaxVersionInclusive = 512;
+
+        // The root registry key for the dependency extension. We write to Software\Classes explicitly
+        // based on the current security context instead of HKCR. See
+        // http://msdn.microsoft.com/en-us/library/ms724475(VS.85).aspx for more information.
+        internal static readonly string RegistryRoot = @"Software\Classes\Installer\Dependencies\";
+        internal static readonly string RegistryDependents = "Dependents";
+
+        // The following characters cannot be used in a provider key.
+        internal static readonly char[] InvalidCharacters = new char[] { ' ', '\"', ';', '\\' };
+    }
+}
diff --git a/src/wixext/DependencyCompiler.cs b/src/wixext/DependencyCompiler.cs
new file mode 100644
index 00000000..a138c047
--- /dev/null
+++ b/src/wixext/DependencyCompiler.cs
@@ -0,0 +1,615 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
+
+namespace WixToolset.Extensions
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Globalization;
+    using System.Text;
+    using System.Xml.Linq;
+    using WixToolset.Data;
+    using WixToolset.Extensibility;
+
+    /// <summary>
+    /// The compiler for the WiX toolset dependency extension.
+    /// </summary>
+    public sealed class DependencyCompiler : CompilerExtension
+    {
+        /// <summary>
+        /// Package type when parsing the Provides element.
+        /// </summary>
+        private enum PackageType
+        {
+            None,
+            ExePackage,
+            MsiPackage,
+            MspPackage,
+            MsuPackage
+        }
+
+        public DependencyCompiler()
+        {
+            this.Namespace = "http://wixtoolset.org/schemas/v4/wxs/dependency";
+        }
+
+        /// <summary>
+        /// Processes an attribute for the Compiler.
+        /// </summary>
+        /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
+        /// <param name="parentElement">Parent element of attribute.</param>
+        /// <param name="attribute">Attribute to process.</param>
+        public override void ParseAttribute(XElement parentElement, XAttribute attribute, IDictionary<string, string> context)
+        {
+            SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(parentElement);
+            switch (parentElement.Name.LocalName)
+            {
+                case "Bundle":
+                    switch (attribute.Name.LocalName)
+                    {
+                        case "ProviderKey":
+                            this.ParseProviderKeyAttribute(sourceLineNumbers, parentElement, attribute);
+                            break;
+                        default:
+                            this.Core.UnexpectedAttribute(parentElement, attribute);
+                            break;
+                    }
+                    break;
+                default:
+                    this.Core.UnexpectedAttribute(parentElement, attribute);
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Processes an element for the Compiler.
+        /// </summary>
+        /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
+        /// <param name="parentElement">Parent element of element to process.</param>
+        /// <param name="element">Element to process.</param>
+        /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
+        public override void ParseElement(XElement parentElement, XElement element, IDictionary<string, string> context)
+        {
+            PackageType packageType = PackageType.None;
+
+            switch (parentElement.Name.LocalName)
+            {
+                case "Bundle":
+                case "Fragment":
+                case "Module":
+                case "Product":
+                    switch (element.Name.LocalName)
+                    {
+                        case "Requires":
+                            this.ParseRequiresElement(element, null, false);
+                            break;
+                        default:
+                            this.Core.UnexpectedElement(parentElement, element);
+                            break;
+                    }
+                    break;
+                case "ExePackage":
+                    packageType = PackageType.ExePackage;
+                    break;
+                case "MsiPackage":
+                    packageType = PackageType.MsiPackage;
+                    break;
+                case "MspPackage":
+                    packageType = PackageType.MspPackage;
+                    break;
+                case "MsuPackage":
+                    packageType = PackageType.MsuPackage;
+                    break;
+                default:
+                    this.Core.UnexpectedElement(parentElement, element);
+                    break;
+            }
+
+            if (PackageType.None != packageType)
+            {
+                string packageId = context["PackageId"];
+
+                switch (element.Name.LocalName)
+                {
+                    case "Provides":
+                        this.ParseProvidesElement(element, packageType, packageId);
+                        break;
+                    default:
+                        this.Core.UnexpectedElement(parentElement, element);
+                        break;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Processes a child element of a Component for the Compiler.
+        /// </summary>
+        /// <param name="parentElement">Parent element of element to process.</param>
+        /// <param name="element">Element to process.</param>
+        /// <param name="context">Extra information about the context in which this element is being parsed.</param>
+        /// <returns>The component key path type if set.</returns>
+        public override ComponentKeyPath ParsePossibleKeyPathElement(XElement parentElement, XElement element, IDictionary<string, string> context)
+        {
+            SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(parentElement);
+            ComponentKeyPath keyPath = null;
+
+            switch (parentElement.Name.LocalName)
+            {
+                case "Component":
+                    string componentId = context["ComponentId"];
+
+                    // 64-bit components may cause issues downlevel.
+                    bool win64 = false;
+                    Boolean.TryParse(context["Win64"], out win64);
+
+                    switch (element.Name.LocalName)
+                    {
+                        case "Provides":
+                            if (win64)
+                            {
+                                this.Core.OnMessage(DependencyWarnings.Win64Component(sourceLineNumbers, componentId));
+                            }
+
+                            keyPath = this.ParseProvidesElement(element, PackageType.None, componentId);
+                            break;
+                        default:
+                            this.Core.UnexpectedElement(parentElement, element);
+                            break;
+                    }
+                    break;
+                default:
+                    this.Core.UnexpectedElement(parentElement, element);
+                    break;
+            }
+
+            return keyPath;
+        }
+
+        /// <summary>
+        /// Processes the ProviderKey bundle attribute.
+        /// </summary>
+        /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
+        /// <param name="parentElement">Parent element of attribute.</param>
+        /// <param name="attribute">The XML attribute for the ProviderKey attribute.</param>
+        private void ParseProviderKeyAttribute(SourceLineNumber sourceLineNumbers, XElement parentElement, XAttribute attribute)
+        {
+            Identifier id = null;
+            string providerKey = null;
+            int illegalChar = -1;
+
+            switch (attribute.Name.LocalName)
+            {
+                case "ProviderKey":
+                    providerKey = this.Core.GetAttributeValue(sourceLineNumbers, attribute);
+                    break;
+                default:
+                    this.Core.UnexpectedAttribute(parentElement, attribute);
+                    break;
+            }
+
+            // Make sure the key does not contain any illegal characters or values.
+            if (String.IsNullOrEmpty(providerKey))
+            {
+                this.Core.OnMessage(WixErrors.IllegalEmptyAttributeValue(sourceLineNumbers, parentElement.Name.LocalName, attribute.Name.LocalName));
+            }
+            else if (0 <= (illegalChar = providerKey.IndexOfAny(DependencyCommon.InvalidCharacters)))
+            {
+                StringBuilder sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2);
+                Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" "));
+
+                this.Core.OnMessage(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "ProviderKey", providerKey[illegalChar], sb.ToString()));
+            }
+            else if ("ALL" == providerKey)
+            {
+                this.Core.OnMessage(DependencyErrors.ReservedValue(sourceLineNumbers, parentElement.Name.LocalName, "ProviderKey", providerKey));
+            }
+
+            // Generate the primary key for the row.
+            id = this.Core.CreateIdentifier("dep", attribute.Name.LocalName, providerKey);
+
+            if (!this.Core.EncounteredError)
+            {
+                // Create the provider row for the bundle. The Component_ field is required
+                // in the table definition but unused for bundles, so just set it to the valid ID.
+                Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyProvider", id);
+                row[1] = id.Id;
+                row[2] = providerKey;
+                row[5] = DependencyCommon.ProvidesAttributesBundle;
+            }
+        }
+
+        /// <summary>
+        /// Processes the Provides element.
+        /// </summary>
+        /// <param name="node">The XML node for the Provides element.</param>
+        /// <param name="packageType">The type of the package being chained into a bundle, or "None" if building an MSI package.</param>
+        /// <param name="keyPath">Explicit key path.</param>
+        /// <param name="parentId">The identifier of the parent component or package.</param>
+        /// <returns>The type of key path if set.</returns>
+        private ComponentKeyPath ParseProvidesElement(XElement node, PackageType packageType, string parentId)
+        {
+            SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
+            ComponentKeyPath keyPath = null;
+            Identifier id = null;
+            string key = null;
+            string version = null;
+            string displayName = null;
+            int attributes = 0;
+            int illegalChar = -1;
+
+            foreach (XAttribute attrib in node.Attributes())
+            {
+                if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
+                {
+                    switch (attrib.Name.LocalName)
+                    {
+                        case "Id":
+                            id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
+                            break;
+                        case "Key":
+                            key = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
+                            break;
+                        case "Version":
+                            version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
+                            break;
+                        case "DisplayName":
+                            displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
+                            break;
+                        default:
+                            this.Core.UnexpectedAttribute(node, attrib);
+                            break;
+                    }
+                }
+                else
+                {
+                    this.Core.ParseExtensionAttribute(node, attrib);
+                }
+            }
+
+            // Make sure the key is valid. The key will default to the ProductCode for MSI packages
+            // and the package code for MSP packages in the binder if not specified.
+            if (!String.IsNullOrEmpty(key))
+            {
+                // Make sure the key does not contain any illegal characters or values.
+                if (0 <= (illegalChar = key.IndexOfAny(DependencyCommon.InvalidCharacters)))
+                {
+                    StringBuilder sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2);
+                    Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" "));
+
+                    this.Core.OnMessage(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "Key", key[illegalChar], sb.ToString()));
+                }
+                else if ("ALL" == key)
+                {
+                    this.Core.OnMessage(DependencyErrors.ReservedValue(sourceLineNumbers, node.Name.LocalName, "Key", key));
+                }
+            }
+            else if (PackageType.ExePackage == packageType || PackageType.MsuPackage == packageType)
+            {
+                // Must specify the provider key when authored for a package.
+                this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key"));
+            }
+            else if (PackageType.None == packageType)
+            {
+                // Make sure the ProductCode is authored and set the key.
+                this.Core.CreateSimpleReference(sourceLineNumbers, "Property", "ProductCode");
+                key = "!(bind.property.ProductCode)";
+            }
+
+            // The Version attribute should not be authored in or for an MSI package.
+            if (!String.IsNullOrEmpty(version))
+            {
+                switch (packageType)
+                {
+                    case PackageType.None:
+                        this.Core.OnMessage(DependencyWarnings.DiscouragedVersionAttribute(sourceLineNumbers));
+                        break;
+                    case PackageType.MsiPackage:
+                        this.Core.OnMessage(DependencyWarnings.DiscouragedVersionAttribute(sourceLineNumbers, parentId));
+                        break;
+                }
+            }
+            else if (PackageType.MspPackage == packageType || PackageType.MsuPackage == packageType)
+            {
+                // Must specify the Version when authored for packages that do not contain a version.
+                this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
+            }
+
+            // Need the element ID for child element processing, so generate now if not authored.
+            if (null == id)
+            {
+                id = this.Core.CreateIdentifier("dep", node.Name.LocalName, parentId, key);
+            }
+
+            foreach (XElement child in node.Elements())
+            {
+                if (this.Namespace == child.Name.Namespace)
+                {
+                    switch (child.Name.LocalName)
+                    {
+                        case "Requires":
+                            this.ParseRequiresElement(child, id.Id, PackageType.None == packageType);
+                            break;
+                        case "RequiresRef":
+                            this.ParseRequiresRefElement(child, id.Id, PackageType.None == packageType);
+                            break;
+                        default:
+                            this.Core.UnexpectedElement(node, child);
+                            break;
+                    }
+                }
+                else
+                {
+                    this.Core.ParseExtensionElement(node, child);
+                }
+            }
+
+            if (!this.Core.EncounteredError)
+            {
+                // Create the row in the provider table.
+                Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyProvider", id);
+                row[1] = parentId;
+                row[2] = key;
+
+                if (!String.IsNullOrEmpty(version))
+                {
+                    row[3] = version;
+                }
+
+                if (!String.IsNullOrEmpty(displayName))
+                {
+                    row[4] = displayName;
+                }
+
+                if (0 != attributes)
+                {
+                    row[5] = attributes;
+                }
+
+                if (PackageType.None == packageType)
+                {
+                    // Reference the Check custom action to check for dependencies on the current provider.
+                    if (Platform.ARM == this.Core.CurrentPlatform)
+                    {
+                        // Ensure the ARM version of the CA is referenced.
+                        this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyCheck_ARM");
+                    }
+                    else
+                    {
+                        // All other supported platforms use x86.
+                        this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyCheck");
+                    }
+
+                    // Generate registry rows for the provider using binder properties.
+                    string keyProvides = String.Concat(DependencyCommon.RegistryRoot, key);
+
+                    row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "(Default)"));
+                    row[1] = -1;
+                    row[2] = keyProvides;
+                    row[3] = null;
+                    row[4] = "[ProductCode]";
+                    row[5] = parentId;
+
+                    // Use the Version registry value and use that as a potential key path.
+                    Identifier idVersion = this.Core.CreateIdentifier("reg", id.Id, "Version");
+                    keyPath = new ComponentKeyPath() { Id = idVersion.Id, Explicit = false, Type = ComponentKeyPathType.Registry };
+
+                    row = this.Core.CreateRow(sourceLineNumbers, "Registry", idVersion);
+                    row[1] = -1;
+                    row[2] = keyProvides;
+                    row[3] = "Version";
+                    row[4] = !String.IsNullOrEmpty(version) ? version : "[ProductVersion]";
+                    row[5] = parentId;
+
+                    row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "DisplayName"));
+                    row[1] = -1;
+                    row[2] = keyProvides;
+                    row[3] = "DisplayName";
+                    row[4] = !String.IsNullOrEmpty(displayName) ? displayName : "[ProductName]";
+                    row[5] = parentId;
+
+                    if (0 != attributes)
+                    {
+                        row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "Attributes"));
+                        row[1] = -1;
+                        row[2] = keyProvides;
+                        row[3] = "Attributes";
+                        row[4] = String.Concat("#", attributes.ToString(CultureInfo.InvariantCulture.NumberFormat));
+                        row[5] = parentId;
+                    }
+                }
+            }
+
+            return keyPath;
+        }
+
+        /// <summary>
+        /// Processes the Requires element.
+        /// </summary>
+        /// <param name="node">The XML node for the Requires element.</param>
+        /// <param name="providerId">The parent provider identifier.</param>
+        /// <param name="requiresAction">Whether the Requires custom action should be referenced.</param>
+        private void ParseRequiresElement(XElement node, string providerId, bool requiresAction)
+        {
+            SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
+            Identifier id = null;
+            string providerKey = null;
+            string minVersion = null;
+            string maxVersion = null;
+            int attributes = 0;
+            int illegalChar = -1;
+
+            foreach (XAttribute attrib in node.Attributes())
+            {
+                if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
+                {
+                    switch (attrib.Name.LocalName)
+                    {
+                        case "Id":
+                            id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
+                            break;
+                        case "ProviderKey":
+                            providerKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
+                            break;
+                        case "Minimum":
+                            minVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
+                            break;
+                        case "Maximum":
+                            maxVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
+                            break;
+                        case "IncludeMinimum":
+                            if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
+                            {
+                                attributes |= DependencyCommon.RequiresAttributesMinVersionInclusive;
+                            }
+                            break;
+                        case "IncludeMaximum":
+                            if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
+                            {
+                                attributes |= DependencyCommon.RequiresAttributesMaxVersionInclusive;
+                            }
+                            break;
+                        default:
+                            this.Core.UnexpectedAttribute(node, attrib);
+                            break;
+                    }
+                }
+                else
+                {
+                    this.Core.ParseExtensionAttribute(node, attrib);
+                }
+            }
+
+            this.Core.ParseForExtensionElements(node);
+
+            if (null == id)
+            {
+                // Generate an ID only if this element is authored under a Provides element; otherwise, a RequiresRef
+                // element will be necessary and the Id attribute will be required.
+                if (!String.IsNullOrEmpty(providerId))
+                {
+                    id = this.Core.CreateIdentifier("dep", node.Name.LocalName, providerKey);
+                }
+                else
+                {
+                    this.Core.OnMessage(WixErrors.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Id", "Provides"));
+                    id = Identifier.Invalid;
+                }
+            }
+
+            if (String.IsNullOrEmpty(providerKey))
+            {
+                this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProviderKey"));
+            }
+            // Make sure the key does not contain any illegal characters.
+            else if (0 <= (illegalChar = providerKey.IndexOfAny(DependencyCommon.InvalidCharacters)))
+            {
+                StringBuilder sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2);
+                Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" "));
+
+                this.Core.OnMessage(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "ProviderKey", providerKey[illegalChar], sb.ToString()));
+            }
+
+
+            if (!this.Core.EncounteredError)
+            {
+                // Reference the Require custom action if required.
+                if (requiresAction)
+                {
+                    if (Platform.ARM == this.Core.CurrentPlatform)
+                    {
+                        // Ensure the ARM version of the CA is referenced.
+                        this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire_ARM");
+                    }
+                    else
+                    {
+                        // All other supported platforms use x86.
+                        this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire");
+                    }
+                }
+
+                Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependency", id);
+                row[1] = providerKey;
+                row[2] = minVersion;
+                row[3] = maxVersion;
+
+                if (0 != attributes)
+                {
+                    row[4] = attributes;
+                }
+
+                // Create the relationship between this WixDependency row and the WixDependencyProvider row.
+                if (!String.IsNullOrEmpty(providerId))
+                {
+                    // Create the relationship between the WixDependency row and the parent WixDependencyProvider row.
+                    row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyRef");
+                    row[0] = providerId;
+                    row[1] = id.Id;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Processes the RequiresRef element.
+        /// </summary>
+        /// <param name="node">The XML node for the RequiresRef element.</param>
+        /// <param name="providerId">The parent provider identifier.</param>
+        /// <param name="requiresAction">Whether the Requires custom action should be referenced.</param>
+        private void ParseRequiresRefElement(XElement node, string providerId, bool requiresAction)
+        {
+            SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
+            string id = null;
+
+            foreach (XAttribute attrib in node.Attributes())
+            {
+                if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
+                {
+                    switch (attrib.Name.LocalName)
+                    {
+                        case "Id":
+                            id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
+                            break;
+                        default:
+                            this.Core.UnexpectedAttribute(node, attrib);
+                            break;
+                    }
+                }
+                else
+                {
+                    this.Core.ParseExtensionAttribute(node, attrib);
+                }
+            }
+
+            this.Core.ParseForExtensionElements(node);
+
+            if (String.IsNullOrEmpty(id))
+            {
+                this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
+            }
+
+            if (!this.Core.EncounteredError)
+            {
+                // Reference the Require custom action if required.
+                if (requiresAction)
+                {
+                    if (Platform.ARM == this.Core.CurrentPlatform)
+                    {
+                        // Ensure the ARM version of the CA is referenced.
+                        this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire_ARM");
+                    }
+                    else
+                    {
+                        // All other supported platforms use x86.
+                        this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire");
+                    }
+                }
+
+                // Create a link dependency on the row that contains information we'll need during bind.
+                this.Core.CreateSimpleReference(sourceLineNumbers, "WixDependency", id);
+
+                // Create the relationship between the WixDependency row and the parent WixDependencyProvider row.
+                Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyRef");
+                row[0] = providerId;
+                row[1] = id;
+            }
+        }
+    }
+}
diff --git a/src/wixext/DependencyDecompiler.cs b/src/wixext/DependencyDecompiler.cs
new file mode 100644
index 00000000..3013cf7c
--- /dev/null
+++ b/src/wixext/DependencyDecompiler.cs
@@ -0,0 +1,345 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
+
+namespace WixToolset.Extensions
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Collections.ObjectModel;
+    using WixToolset;
+    using WixToolset.Data;
+    using WixToolset.Extensibility;
+    using WixToolset.Extensions.Serialize.Dependency;
+    using Dependency = WixToolset.Extensions.Serialize.Dependency;
+    using Wix = WixToolset.Data.Serialize;
+
+    /// <summary>
+    /// The decompiler for the WiX toolset dependency extension.
+    /// </summary>
+    public sealed class DependencyDecompiler : DecompilerExtension
+    {
+        private RegistryKeyValueCollection registryValues;
+        private Dictionary<string, string> keyCache;
+
+        /// <summary>
+        /// Creates a new instance of the <see cref="DependencyDecompiler"/> class.
+        /// </summary>
+        public DependencyDecompiler()
+        {
+            this.registryValues = new RegistryKeyValueCollection();
+            this.keyCache = new Dictionary<string, string>();
+
+            this.TableDefinitions = DependencyExtensionData.GetExtensionTableDefinitions();
+        }
+
+        /// <summary>
+        /// Get the extensions library to be removed.
+        /// </summary>
+        /// <param name="tableDefinitions">Table definitions for library.</param>
+        /// <returns>Library to remove from decompiled output.</returns>
+        public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
+        {
+            return DependencyExtensionData.GetExtensionLibrary(tableDefinitions);
+        }
+
+        /// <summary>
+        /// Decompiles an extension table.
+        /// </summary>
+        /// <param name="table">The table to decompile.</param>
+        public override void DecompileTable(Table table)
+        {
+            switch (table.Name)
+            {
+                case "WixDependencyProvider":
+                    this.DecompileWixDependencyProviderTable(table);
+                    break;
+
+                case "WixDependency":
+                    this.DecompileWixDependencyTable(table);
+                    break;
+
+                case "WixDependencyRef":
+                    this.DecompileWixDependencyRefTable(table);
+                    break;
+
+                default:
+                    base.DecompileTable(table);
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Finalize decompilation by removing registry values that the compiler writes.
+        /// </summary>
+        /// <param name="tables">The collection of all tables.</param>
+        public override void Finish(TableIndexedCollection tables)
+        {
+            // Remove generated registry rows.
+            this.FinalizeRegistryTable(tables);
+
+            // Remove extension properties.
+            this.FinalizeProperties();
+        }
+
+        /// <summary>
+        /// Decompiles the WixDependencyProvider table.
+        /// </summary>
+        /// <param name="table">The table to decompile.</param>
+        private void DecompileWixDependencyProviderTable(Table table)
+        {
+            foreach (Row row in table.Rows)
+            {
+                Provides provides = new Provides();
+
+                provides.Id = (string)row[0];
+                provides.Key = (string)row[2];
+
+                if (null != row[3])
+                {
+                    provides.Version = (string)row[3];
+                }
+
+                if (null != row[4])
+                {
+                    provides.DisplayName = (string)row[4];
+                }
+
+                // Nothing to parse for attributes currently.
+
+                Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
+                if (null != component)
+                {
+                    component.AddChild(provides);
+                }
+                else
+                {
+                    this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
+                }
+
+                // Index the provider to parent the RequiresRef elements.
+                this.Core.IndexElement(row, provides);
+
+                // Add the provider-specific registry keys to be removed during finalization.
+                // Only remove specific keys that the compiler writes.
+                string keyProvides = String.Concat(DependencyCommon.RegistryRoot, provides.Key);
+
+                this.registryValues.Add(keyProvides, null);
+                this.registryValues.Add(keyProvides, "Version");
+                this.registryValues.Add(keyProvides, "DisplayName");
+                this.registryValues.Add(keyProvides, "Attributes");
+
+                // Cache the provider key.
+                this.keyCache[provides.Id] = provides.Key;
+            }
+        }
+
+        /// <summary>
+        /// Decompiles the WixDependency table.
+        /// </summary>
+        /// <param name="table">The table to decompile.</param>
+        private void DecompileWixDependencyTable(Table table)
+        {
+            foreach (Row row in table.Rows)
+            {
+                Requires requires = new Requires();
+
+                requires.Id = (string)row[0];
+                requires.ProviderKey = (string)row[1];
+
+                if (null != row[2])
+                {
+                    requires.Minimum = (string)row[2];
+                }
+
+                if (null != row[3])
+                {
+                    requires.Maximum = (string)row[3];
+                }
+
+                if (null != row[4])
+                {
+                    int attributes = (int)row[4];
+
+                    if (0 != (attributes & DependencyCommon.RequiresAttributesMinVersionInclusive))
+                    {
+                        requires.IncludeMinimum = Dependency.YesNoType.yes;
+                    }
+
+                    if (0 != (attributes & DependencyCommon.RequiresAttributesMaxVersionInclusive))
+                    {
+                        requires.IncludeMaximum = Dependency.YesNoType.yes;
+                    }
+                }
+
+                this.Core.RootElement.AddChild(requires);
+
+                // Cache the requires key.
+                this.keyCache[requires.Id] = requires.ProviderKey;
+            }
+        }
+
+        /// <summary>
+        /// Decompiles the WixDependencyRef table.
+        /// </summary>
+        /// <param name="table">The table to decompile.</param>
+        private void DecompileWixDependencyRefTable(Table table)
+        {
+            foreach (Row row in table.Rows)
+            {
+                RequiresRef requiresRef = new RequiresRef();
+
+                requiresRef.Id = (string)row[1];
+
+                Provides provides = (Provides)this.Core.GetIndexedElement("WixDependencyProvider", (string)row[0]);
+                if (null != provides)
+                {
+                    provides.AddChild(requiresRef);
+                }
+                else
+                {
+                    this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "WixDependencyProvider_", (string)row[0], "WixDependencyProvider"));
+                }
+
+                // Get the cached keys for the provider and dependency IDs and generate registry rows.
+                string providesKey = null;
+                string requiresKey = null;
+
+                if (null != provides && this.keyCache.ContainsKey(provides.Id))
+                {
+                    providesKey = this.keyCache[provides.Id];
+                }
+                else
+                {
+                    this.Core.OnMessage(DependencyWarnings.ProvidesKeyNotFound(row.SourceLineNumbers, provides.Id));
+                }
+
+                if (this.keyCache.ContainsKey(requiresRef.Id))
+                {
+                    requiresKey = this.keyCache[requiresRef.Id];
+                }
+                else
+                {
+                    this.Core.OnMessage(DependencyWarnings.RequiresKeyNotFound(row.SourceLineNumbers, requiresRef.Id));
+                }
+
+                if (!this.Core.EncounteredError)
+                {
+                    // Add the dependency-specific registry keys to be removed during finalization.
+                    // Only remove specific keys that the compiler writes.
+                    string keyRequires = String.Format(@"{0}{1}\{2}\{3}", DependencyCommon.RegistryRoot, requiresKey, DependencyCommon.RegistryDependents, providesKey);
+
+                    this.registryValues.Add(keyRequires, "*");
+                    this.registryValues.Add(keyRequires, "MinVersion");
+                    this.registryValues.Add(keyRequires, "MaxVersion");
+                    this.registryValues.Add(keyRequires, "Attributes");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Removes rows from the Registry table that are generated by this extension.
+        /// </summary>
+        /// <param name="tables">The collection of tables.</param>
+        private void FinalizeRegistryTable(TableIndexedCollection tables)
+        {
+            Table registryTable = tables["Registry"];
+            if (null != registryTable)
+            {
+                foreach (Row registryRow in registryTable.Rows)
+                {
+                    // Check if the compiler writes this registry value; if so, it should be removed.
+                    if (this.registryValues.Contains(registryRow))
+                    {
+                        Wix.ISchemaElement elem = this.Core.GetIndexedElement(registryRow);
+
+                        // If the registry row was found, remove it from its parent.
+                        if (null != elem && null != elem.ParentElement)
+                        {
+                            Wix.IParentElement elemParent = elem.ParentElement as Wix.IParentElement;
+                            if (null != elemParent)
+                            {
+                                elemParent.RemoveChild(elem);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Removes properties defined by this extension.
+        /// </summary>
+        /// <param name="tables">The collection of tables.</param>
+        private void FinalizeProperties()
+        {
+            string[] properties = new string[] { "DISABLEDEPENDENCYCHECK", "IGNOREDEPENDENCIES" };
+            foreach (string property in properties)
+            {
+                Wix.Property elem = this.Core.GetIndexedElement("Property", property) as Wix.Property;
+                if (null != elem)
+                {
+                    // If a value is defined, log a warning we're removing it.
+                    if (!String.IsNullOrEmpty(elem.Value))
+                    {
+                        this.Core.OnMessage(DependencyWarnings.PropertyRemoved(elem.Id));
+                    }
+
+                    // If the property row was found, remove it from its parent.
+                    if (null != elem.ParentElement)
+                    {
+                        Wix.IParentElement elemParent = elem.ParentElement as Wix.IParentElement;
+                        if (null != elemParent)
+                        {
+                            elemParent.RemoveChild(elem);
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Provides an O(1) lookup for registry key and value name pairs for use in the decompiler.
+        /// </summary>
+        private sealed class RegistryKeyValueCollection : KeyedCollection<int, KeyValuePair<string, string>>
+        {
+            /// <summary>
+            /// Adds the registry key and value name pair to the collection if it doesn't already exist.
+            /// </summary>
+            /// <param name="key">The registry key to add.</param>
+            /// <param name="name">The registry value name to add.</param>
+            internal void Add(string key, string name)
+            {
+                KeyValuePair<string, string> pair = new KeyValuePair<string, string>(key, name);
+                if (!this.Contains(pair))
+                {
+                    this.Add(pair);
+                }
+            }
+
+            /// <summary>
+            /// Returns whether the collection contains the registry key and value name pair from the <see cref="Row"/>.
+            /// </summary>
+            /// <param name="row">The registry <see cref="Row"/> to search for.</param>
+            /// <returns>True if the collection contains the registry key and value name pair from the <see cref="Row"/>; otherwise, false.</returns>
+            internal bool Contains(Row row)
+            {
+                if (null == row)
+                {
+                    return false;
+                }
+
+                KeyValuePair<string, string> pair = new KeyValuePair<string, string>((string)row[2], (string)row[3]);
+                return this.Contains(pair);
+            }
+
+            /// <summary>
+            /// Return the hash code of the key and value pair concatenated with a colon as a delimiter.
+            /// </summary>
+            /// <param name="pair">The registry key and value name pair.</param>
+            /// <returns></returns>
+            protected override int GetKeyForItem(KeyValuePair<string, string> pair)
+            {
+                return String.Concat(pair.Key, ":", pair.Value).GetHashCode();
+            }
+        }
+    }
+}
diff --git a/src/wixext/DependencyExtension.csproj b/src/wixext/DependencyExtension.csproj
new file mode 100644
index 00000000..050e8662
--- /dev/null
+++ b/src/wixext/DependencyExtension.csproj
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
+
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+  <PropertyGroup>
+    <ProjectGuid>{A0B6D3F1-AE5E-423B-BA92-60C9926CA498}</ProjectGuid>
+    <AssemblyName>WixDependencyExtension</AssemblyName>
+    <OutputType>Library</OutputType>
+    <RootNamespace>WixToolset.Extensions</RootNamespace>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="AssemblyInfo.cs" />
+    <Compile Include="DependencyBinder.cs" />
+    <Compile Include="DependencyCommon.cs" />
+    <Compile Include="DependencyCompiler.cs" />
+    <Compile Include="DependencyDecompiler.cs" />
+    <Compile Include="DependencyExtensionData.cs" />
+    <EmbeddedFlattenedResource Include="Data\tables.xml">
+      <LogicalName>$(RootNamespace).Data.tables.xml</LogicalName>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </EmbeddedFlattenedResource>
+    <MsgGenSource Include="Data\messages.xml">
+      <ResourcesLogicalName>$(RootNamespace).Data.Messages.resources</ResourcesLogicalName>
+    </MsgGenSource>
+    <EmbeddedFlattenedResource Include="Xsd\Dependency.xsd">
+      <LogicalName>$(RootNamespace).Xsd.Dependency.xsd</LogicalName>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </EmbeddedFlattenedResource>
+    <XsdGenSource Include="Xsd\Dependency.xsd">
+      <CommonNamespace>WixToolset.Data.Serialize</CommonNamespace>
+      <Namespace>WixToolset.Extensions.Serialize.Dependency</Namespace>
+    </XsdGenSource>
+    <EmbeddedResource Include="$(OutputPath)Dependency.wixlib">
+      <Link>Data\Dependency.wixlib</Link>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Xml.Linq" />
+    <ProjectReference Include="..\..\..\libs\WixToolset.Data\WixToolset.Data.csproj" />
+    <ProjectReference Include="..\..\..\libs\WixToolset.Extensibility\WixToolset.Extensibility.csproj" />
+    <ProjectReference Include="..\..\..\tools\wix\Wix.csproj" />
+    <ProjectReference Include="..\wixlib\DependencyExtension.wixproj">
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
+</Project>
diff --git a/src/wixext/DependencyExtensionData.cs b/src/wixext/DependencyExtensionData.cs
new file mode 100644
index 00000000..da2215ce
--- /dev/null
+++ b/src/wixext/DependencyExtensionData.cs
@@ -0,0 +1,64 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
+
+namespace WixToolset.Extensions
+{
+    using System;
+    using System.Reflection;
+    using WixToolset.Data;
+    using WixToolset.Extensibility;
+
+    /// <summary>
+    /// The WiX toolset dependency extension.
+    /// </summary>
+    public sealed class DependencyExtensionData : ExtensionData
+    {
+        /// <summary>
+        /// Gets the default culture.
+        /// </summary>
+        /// <value>The default culture.</value>
+        public override string DefaultCulture
+        {
+            get { return "en-us"; }
+        }
+
+        /// <summary>
+        /// Gets the optional table definitions for this extension.
+        /// </summary>
+        /// <value>The optional table definitions for this extension.</value>
+        public override TableDefinitionCollection TableDefinitions
+        {
+            get
+            {
+                return DependencyExtensionData.GetExtensionTableDefinitions();
+            }
+        }
+
+        /// <summary>
+        /// Gets the library associated with this extension.
+        /// </summary>
+        /// <param name="tableDefinitions">The table definitions to use while loading the library.</param>
+        /// <returns>The loaded library.</returns>
+        public override Library GetLibrary(TableDefinitionCollection tableDefinitions)
+        {
+            return DependencyExtensionData.GetExtensionLibrary(tableDefinitions);
+        }
+
+        /// <summary>
+        /// Internal mechanism to access the extension's table definitions.
+        /// </summary>
+        /// <returns>Extension's table definitions.</returns>
+        internal static TableDefinitionCollection GetExtensionTableDefinitions()
+        {
+            return ExtensionData.LoadTableDefinitionHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.tables.xml");
+        }
+
+        /// <summary>
+        /// Internal mechanism to access the extension's library.
+        /// </summary>
+        /// <returns>Extension's library.</returns>
+        internal static Library GetExtensionLibrary(TableDefinitionCollection tableDefinitions)
+        {
+            return ExtensionData.LoadLibraryHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.Dependency.wixlib", tableDefinitions);
+        }
+    }
+}
diff --git a/src/wixext/messages.xml b/src/wixext/messages.xml
new file mode 100644
index 00000000..bd6eb602
--- /dev/null
+++ b/src/wixext/messages.xml
@@ -0,0 +1,60 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
+
+
+<Messages Namespace="WixToolset.Extensions" Resources="Data.Messages" xmlns="http://schemas.microsoft.com/genmsgs/2004/07/messages">
+    <Class Name="DependencyErrors" ContainerName="DependencyErrorEventArgs" BaseContainerName="MessageEventArgs">
+        <Message Id="IllegalCharactersInProvider" Number="5400">
+            <Instance>
+                The provider key authored into the {0} attribute contains an illegal character, '{1}'. Please author the provider key without any of the following characters: {2}
+                <Parameter Type="System.String" Name="attributeName" />
+                <Parameter Type="System.Char" Name="illegalChar" />
+                <Parameter Type="System.String" Name="illegalChars" />
+            </Instance>
+        </Message>
+        <Message Id="ReservedValue" Number="5401">
+            <Instance>
+                The {0}/@{1} attribute value '{2}' is reserved and cannot be used here. Please choose a different value.
+                <Parameter Type="System.String" Name="elementName" />
+                <Parameter Type="System.String" Name="attributeName" />
+                <Parameter Type="System.String" Name="attributeValue" />
+            </Instance>
+        </Message>
+    </Class>
+    <Class Name="DependencyWarnings" ContainerName="DependencyWarningEventArgs" BaseContainerName="MessageEventArgs">
+        <Message Id="ProvidesKeyNotFound" Number="5431">
+            <Instance>
+                The provider key with identifier {0} was not found in the WixDependencyProvider table. Related registry rows will not be removed from authoring.
+                <Parameter Type="System.String" Name="id" />
+            </Instance>
+        </Message>
+        <Message Id="RequiresKeyNotFound" Number="5432">
+            <Instance>
+                The dependency key with identifier {0} was not found in the WixDependency table. Related registry rows will not be removed from authoring.
+                <Parameter Type="System.String" Name="id" />
+            </Instance>
+        </Message>
+        <Message Id="PropertyRemoved" Number="5433" SourceLineNumbers="no">
+            <Instance>
+                The property {0} was authored in the package with a value and will be removed. The property should not be authored.
+                <Parameter Type="System.String" Name="name" />
+            </Instance>
+        </Message>
+        <Message Id="DiscouragedVersionAttribute" Number="5434">
+            <Instance>
+                The Provides/@Version attribute should not be specified in an MSI package. The ProductVersion will be used by default.
+            </Instance>
+            <Instance>
+                The Provides/@Version attribute should not be specified for MSI package {0}. The ProductVersion will be used by default.
+                <Parameter Type="System.String" Name="id" />
+            </Instance>
+        </Message>
+        <Message Id="Win64Component" Number="5435">
+            <Instance>
+                The Provides element should not be authored in the 64-bit component with identifier {0}. The dependency feature may not work if installing this package on 64-bit Windows operating systems prior to Windows 7 and Windows Server 2008 R2. Set the Component/@Win64 attribute to "no" to make sure the dependency feature works correctly on all supported operating systems.
+                <Parameter Type="System.String" Name="componentId" />
+            </Instance>
+        </Message>
+    </Class>
+    <Class Name="DependencyVerboses" ContainerName="DependencyVerboseEventArgs" BaseContainerName="MessageEventArgs" />
+</Messages>
diff --git a/src/wixext/tables.xml b/src/wixext/tables.xml
new file mode 100644
index 00000000..03c9f267
--- /dev/null
+++ b/src/wixext/tables.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
+
+
+<tableDefinitions xmlns="http://wixtoolset.org/schemas/v4/wi/tables">
+    <tableDefinition name="WixDependencyProvider" createSymbols="yes">
+        <columnDefinition name="WixDependencyProvider" type="string" length="72" primaryKey="yes" modularize="column"
+                category="identifier" description="The non-localized primary key for the table."/>
+        <columnDefinition name="Component_" type="string" length="72" keyTable="Component" keyColumn="1" modularize="column"
+                category="identifier" description="The foreign key into the Component table used to determine install state."/>
+        <columnDefinition name="ProviderKey" type="string" length="255"
+                category="text" description="The name of the registry key that holds the provider identity."/>
+        <columnDefinition name="Version" type="string" length="72" nullable="yes"
+                category="version" description="The version of the package."/>
+        <columnDefinition name="DisplayName" type="string" length="255" nullable="yes"
+                category="text" description="The display name of the package."/>
+        <columnDefinition name="Attributes" type="number" length="4" nullable="yes"
+                minValue="0" maxValue="2147483647" description="A 32-bit word that specifies the attribute flags to be applied."/>
+    </tableDefinition>
+    <tableDefinition name="WixDependency" createSymbols="yes">
+        <columnDefinition name="WixDependency" type="string" length="72" primaryKey="yes" modularize="column"
+                category="identifier" description="The non-localized primary key for the table."/>
+        <columnDefinition name="ProviderKey" type="string" length="255"
+                category="text" description="The name of the registry key that holds the provider identity."/>
+        <columnDefinition name="MinVersion" type="string" length="72" nullable="yes"
+                category="version" description="The minimum version of the provider supported."/>
+        <columnDefinition name="MaxVersion" type="string" length="72" nullable="yes"
+                category="version" description="The maximum version of the provider supported."/>
+        <columnDefinition name="Attributes" type="number" length="4" nullable="yes"
+                minValue="0" maxValue="2147483647" description="A 32-bit word that specifies the attribute flags to be applied."/>
+    </tableDefinition>
+    <tableDefinition name="WixDependencyRef" createSymbols="yes">
+        <columnDefinition name="WixDependencyProvider_" type="string" length="72" primaryKey="yes" keyTable="WixDependencyProvider" keyColumn="1" modularize="column"
+                category="identifier" description="Foreign key into the Component table." />
+        <columnDefinition name="WixDependency_" type="string" length="72" primaryKey="yes" keyTable="WixDependency" keyColumn="1" modularize="column"
+                category="identifier" description="Foreign key into the WixDependency table." />
+    </tableDefinition>
+</tableDefinitions>
-- 
cgit v1.2.3-55-g6feb