diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2019-02-03 13:20:43 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2019-02-03 13:20:43 -0600 |
commit | 72f3dceefa2e3893b061e074380794bc60b67b6f (patch) | |
tree | 74b812780e2e16b4e30764d92f6294958413ac6f /src/wixext | |
parent | d2f21865933c11b8af80b8383e1dbf611a175133 (diff) | |
download | wix-72f3dceefa2e3893b061e074380794bc60b67b6f.tar.gz wix-72f3dceefa2e3893b061e074380794bc60b67b6f.tar.bz2 wix-72f3dceefa2e3893b061e074380794bc60b67b6f.zip |
Import code from old v4 repo
Diffstat (limited to 'src/wixext')
-rw-r--r-- | src/wixext/Dependency.xsd | 226 | ||||
-rw-r--r-- | src/wixext/DependencyBinder.cs | 169 | ||||
-rw-r--r-- | src/wixext/DependencyCommon.cs | 26 | ||||
-rw-r--r-- | src/wixext/DependencyCompiler.cs | 615 | ||||
-rw-r--r-- | src/wixext/DependencyDecompiler.cs | 345 | ||||
-rw-r--r-- | src/wixext/DependencyExtension.csproj | 50 | ||||
-rw-r--r-- | src/wixext/DependencyExtensionData.cs | 64 | ||||
-rw-r--r-- | src/wixext/messages.xml | 60 | ||||
-rw-r--r-- | src/wixext/tables.xml | 38 |
9 files changed, 1593 insertions, 0 deletions
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 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | |||
5 | <xs:schema xmlns:html="http://www.w3.org/1999/xhtml" | ||
6 | xmlns:wix="http://wixtoolset.org/schemas/v4/wxs" | ||
7 | xmlns:xs="http://www.w3.org/2001/XMLSchema" | ||
8 | xmlns:xse=" http://wixtoolset.org/schemas/XmlSchemaExtension" | ||
9 | targetNamespace="http://wixtoolset.org/schemas/v4/wxs/dependency" | ||
10 | xmlns="http://wixtoolset.org/schemas/v4/wxs/dependency"> | ||
11 | <xs:annotation> | ||
12 | <xs:documentation> | ||
13 | The source code schema for the WiX Toolset Dependency Extension. | ||
14 | </xs:documentation> | ||
15 | </xs:annotation> | ||
16 | <xs:element name="Provides"> | ||
17 | <xs:annotation> | ||
18 | <xs:documentation> | ||
19 | Describes the information for this product or feature that serves as a dependency of other products or features. | ||
20 | </xs:documentation> | ||
21 | <xs:appinfo> | ||
22 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Component" /> | ||
23 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="ExePackage" /> | ||
24 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="MsiPackage" /> | ||
25 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="MspPackage" /> | ||
26 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="MsuPackage" /> | ||
27 | <xse:remarks> | ||
28 | <html:p> | ||
29 | This element is required for any product, feature, or bundle that will use the Dependency feature to properly reference count | ||
30 | other products or features. It should be authored into a component that is always installed and removed with the | ||
31 | product or features that contain it. This guarantees that product dependencies are not removed before those products that | ||
32 | depend on them. | ||
33 | </html:p> | ||
34 | <html:p> | ||
35 | The @Key attribute should identify a version range for your product that you guarantee will be backward compatible. | ||
36 | This key is designed to persist throughout compatible upgrades so that dependent products do not have to be reinstalled | ||
37 | and will not prevent your product from being upgraded. If this attribute is not authored, the value is the ProductCode | ||
38 | and will not automatically support upgrades. | ||
39 | </html:p> | ||
40 | <html:p> | ||
41 | By default this uses the Product/@Id attribute value, which may be automatically generated. | ||
42 | </html:p> | ||
43 | </xse:remarks> | ||
44 | <xse:howtoRef href="author_product_dependencies.html">How To: Author product dependencies</xse:howtoRef> | ||
45 | </xs:appinfo> | ||
46 | </xs:annotation> | ||
47 | <xs:complexType> | ||
48 | <xs:choice minOccurs="0" maxOccurs="unbounded"> | ||
49 | <xs:element ref="Requires" /> | ||
50 | <xs:element ref="RequiresRef" /> | ||
51 | </xs:choice> | ||
52 | <xs:attribute name="Id" type="xs:string"> | ||
53 | <xs:annotation> | ||
54 | <xs:documentation> | ||
55 | Dependency provider identity. If this attribute is not specified, an identifier will be generated automatically. | ||
56 | </xs:documentation> | ||
57 | </xs:annotation> | ||
58 | </xs:attribute> | ||
59 | <xs:attribute name="Key" type="xs:string"> | ||
60 | <xs:annotation> | ||
61 | <xs:documentation> | ||
62 | Optional unique registry key name that identifies a product version range on which other products can depend. | ||
63 | This attribute is required in package authoring, but optional for components. | ||
64 | </xs:documentation> | ||
65 | </xs:annotation> | ||
66 | </xs:attribute> | ||
67 | <xs:attribute name="Version" type="VersionType"> | ||
68 | <xs:annotation> | ||
69 | <xs:documentation> | ||
70 | The version of the package. For MSI packages, the ProductVersion will be used by default | ||
71 | and this attribute should not be specified. | ||
72 | </xs:documentation> | ||
73 | </xs:annotation> | ||
74 | </xs:attribute> | ||
75 | <xs:attribute name="DisplayName" type="xs:string"> | ||
76 | <xs:annotation> | ||
77 | <xs:documentation> | ||
78 | Optional display name of the package. For MSI packages, the ProductName will be used by default. | ||
79 | </xs:documentation> | ||
80 | </xs:annotation> | ||
81 | </xs:attribute> | ||
82 | </xs:complexType> | ||
83 | </xs:element> | ||
84 | <xs:element name="Requires"> | ||
85 | <xs:annotation> | ||
86 | <xs:documentation> | ||
87 | Describes a dependency on a provider for the current component or package. | ||
88 | </xs:documentation> | ||
89 | <xs:appinfo> | ||
90 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" /> | ||
91 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Fragment" /> | ||
92 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Module" /> | ||
93 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Product" /> | ||
94 | <xse:remarks> | ||
95 | <html:p> | ||
96 | This element declares a dependency on any product that uses the Provides element. If that product is uninstalled | ||
97 | before a product that requires it, the uninstall will err or warn the user that other products are installed | ||
98 | which depend on that product. This behavior can be modified by changing the attribute values on the Requires element. | ||
99 | </html:p> | ||
100 | <html:p> | ||
101 | If you do not nest this element under a Provides element, you must specify the @Id attribute | ||
102 | so that it can be referenced by a RequiresRef element nested under a Provides element. | ||
103 | </html:p> | ||
104 | </xse:remarks> | ||
105 | <xse:seeAlso ref="RequiresRef" /> | ||
106 | <xse:howtoRef href="author_product_dependencies.html">How To: Author product dependencies</xse:howtoRef> | ||
107 | </xs:appinfo> | ||
108 | </xs:annotation> | ||
109 | <xs:complexType> | ||
110 | <xs:attribute name="Id" type="xs:string"> | ||
111 | <xs:annotation> | ||
112 | <xs:documentation> | ||
113 | Dependency requirement identity. If this attribute is not specified, an identifier will be generated automatically. | ||
114 | If this element is not authored under a Provides element, this attribute is required. | ||
115 | </xs:documentation> | ||
116 | </xs:annotation> | ||
117 | </xs:attribute> | ||
118 | <xs:attribute name="ProviderKey" type="xs:string" use="required"> | ||
119 | <xs:annotation> | ||
120 | <xs:documentation> | ||
121 | The unique registry key name for the dependency provider to require during installation of this product. | ||
122 | </xs:documentation> | ||
123 | </xs:annotation> | ||
124 | </xs:attribute> | ||
125 | <xs:attribute name="Minimum" type="VersionType"> | ||
126 | <xs:annotation> | ||
127 | <xs:documentation> | ||
128 | The minimum version of the dependency provider required to be installed. The default is unbound. | ||
129 | </xs:documentation> | ||
130 | </xs:annotation> | ||
131 | </xs:attribute> | ||
132 | <xs:attribute name="Maximum" type="VersionType"> | ||
133 | <xs:annotation> | ||
134 | <xs:documentation> | ||
135 | The maximum version of the dependency provider required to be installed. The default is unbound. | ||
136 | </xs:documentation> | ||
137 | </xs:annotation> | ||
138 | </xs:attribute> | ||
139 | <xs:attribute name="IncludeMinimum" type="YesNoType"> | ||
140 | <xs:annotation> | ||
141 | <xs:documentation> | ||
142 | Set to "yes" to make the range of dependency provider versions required include the value specified in Minimum. | ||
143 | </xs:documentation> | ||
144 | </xs:annotation> | ||
145 | </xs:attribute> | ||
146 | <xs:attribute name="IncludeMaximum" type="YesNoType"> | ||
147 | <xs:annotation> | ||
148 | <xs:documentation> | ||
149 | Set to "yes" to make the range of dependency provider versions required include the value specified in Maximum. | ||
150 | </xs:documentation> | ||
151 | </xs:annotation> | ||
152 | </xs:attribute> | ||
153 | </xs:complexType> | ||
154 | </xs:element> | ||
155 | <xs:element name="RequiresRef"> | ||
156 | <xs:annotation> | ||
157 | <xs:documentation> | ||
158 | References existing authoring for a dependency on a provider for the current component or package. | ||
159 | </xs:documentation> | ||
160 | <xs:appinfo> | ||
161 | <xse:remarks> | ||
162 | <html:p> | ||
163 | This element references a dependency on any product that uses the Provides element. If that product is uninstalled | ||
164 | before a product that requires it, the uninstall will err or warn the user that other products are installed | ||
165 | which depend on that product. This behavior can be modified by changing the attribute values on the Requires element. | ||
166 | </html:p> | ||
167 | </xse:remarks> | ||
168 | <xse:seeAlso ref="Requires" /> | ||
169 | <xse:howtoRef href="author_product_dependencies.html">How To: Author product dependencies</xse:howtoRef> | ||
170 | </xs:appinfo> | ||
171 | </xs:annotation> | ||
172 | <xs:complexType> | ||
173 | <xs:attribute name="Id" type="xs:string" use="required"> | ||
174 | <xs:annotation> | ||
175 | <xs:documentation> | ||
176 | The identifier of the Requires element to reference. | ||
177 | </xs:documentation> | ||
178 | </xs:annotation> | ||
179 | </xs:attribute> | ||
180 | </xs:complexType> | ||
181 | </xs:element> | ||
182 | <xs:attribute name="ProviderKey" type="xs:string"> | ||
183 | <xs:annotation> | ||
184 | <xs:documentation> | ||
185 | Optional attribute to explicitly author the provider key for the entire bundle. | ||
186 | </xs:documentation> | ||
187 | <xs:appinfo> | ||
188 | <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" /> | ||
189 | <xse:remarks> | ||
190 | <html:p> | ||
191 | This provider key is designed to persist throughout compatible upgrades so that dependent bundles do not have to be reinstalled | ||
192 | and will not prevent your product from being upgraded. If this attribute is not authored, the value is the | ||
193 | automatically-generated bundle ID and will not automatically support upgrades. | ||
194 | </html:p> | ||
195 | <html:p> | ||
196 | Only a single provider key is supported for bundles. To author that your bundle provides additional features via | ||
197 | packages, author different provider keys for your packages. | ||
198 | </html:p> | ||
199 | </xse:remarks> | ||
200 | <xse:seeAlso ref="Provides" /> | ||
201 | </xs:appinfo> | ||
202 | </xs:annotation> | ||
203 | </xs:attribute> | ||
204 | <xs:simpleType name="VersionType"> | ||
205 | <xs:annotation> | ||
206 | <xs:documentation> | ||
207 | Values of this type will look like: "x.x.x.x" where x is an integer from 0 to 65534. | ||
208 | This can also be a preprocessor, binder, or WiX variable. | ||
209 | </xs:documentation> | ||
210 | </xs:annotation> | ||
211 | <xs:restriction base="xs:string"> | ||
212 | <xs:pattern value="(\d{1,5}\.){3}\d{1,5}|[!$]\((var|bind|wix)\.[_A-Za-z][\w\.]*\)" /> | ||
213 | </xs:restriction> | ||
214 | </xs:simpleType> | ||
215 | <xs:simpleType name="YesNoType"> | ||
216 | <xs:annotation> | ||
217 | <xs:documentation> | ||
218 | Values of this type will either be "yes" or "no". | ||
219 | </xs:documentation> | ||
220 | </xs:annotation> | ||
221 | <xs:restriction base="xs:NMTOKEN"> | ||
222 | <xs:enumeration value="no" /> | ||
223 | <xs:enumeration value="yes" /> | ||
224 | </xs:restriction> | ||
225 | </xs:simpleType> | ||
226 | </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 @@ | |||
1 | // 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. | ||
2 | |||
3 | namespace WixToolset.Extensions | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.ObjectModel; | ||
7 | using System.Globalization; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Extensibility; | ||
10 | |||
11 | /// <summary> | ||
12 | /// The compiler for the WiX toolset dependency extension. | ||
13 | /// </summary> | ||
14 | public sealed class DependencyBinder : BinderExtension | ||
15 | { | ||
16 | private Output output; | ||
17 | |||
18 | /// <summary> | ||
19 | /// Called after all output changes occur and right before the output is bound into its final format. | ||
20 | /// </summary> | ||
21 | public override void Finish(Output output) | ||
22 | { | ||
23 | // Only process MSI packages. | ||
24 | if (OutputType.Product != output.Type) | ||
25 | { | ||
26 | return; | ||
27 | } | ||
28 | |||
29 | this.output = output; | ||
30 | |||
31 | Table wixDependencyTable = output.Tables["WixDependency"]; | ||
32 | Table wixDependencyProviderTable = output.Tables["WixDependencyProvider"]; | ||
33 | Table wixDependencyRefTable = output.Tables["WixDependencyRef"]; | ||
34 | |||
35 | // Make sure there's something to do. | ||
36 | if (null != wixDependencyRefTable) | ||
37 | { | ||
38 | KeyedRowCollection wixDependencyRows = new KeyedRowCollection(wixDependencyTable); | ||
39 | KeyedRowCollection wixDependencyProviderRows = new KeyedRowCollection(wixDependencyProviderTable); | ||
40 | |||
41 | // For each relationship, get the provides and requires rows to generate registry values. | ||
42 | foreach (Row wixDependencyRefRow in wixDependencyRefTable.Rows) | ||
43 | { | ||
44 | string providesId = (string)wixDependencyRefRow[0]; | ||
45 | string requiresId = (string)wixDependencyRefRow[1]; | ||
46 | |||
47 | Row wixDependencyRow = null; | ||
48 | if (wixDependencyRows.Contains(requiresId)) | ||
49 | { | ||
50 | wixDependencyRow = wixDependencyRows[requiresId]; | ||
51 | } | ||
52 | |||
53 | Row wixDependencyProviderRow = null; | ||
54 | if (wixDependencyProviderRows.Contains(providesId)) | ||
55 | { | ||
56 | wixDependencyProviderRow = wixDependencyProviderRows[providesId]; | ||
57 | } | ||
58 | |||
59 | // If we found both rows, generate the registry values. | ||
60 | if (null != wixDependencyRow && null != wixDependencyProviderRow) | ||
61 | { | ||
62 | // Format the root registry key using the required provider key and the current provider key. | ||
63 | string requiresKey = (string)wixDependencyRow[1]; | ||
64 | string providesKey = (string)wixDependencyProviderRow[2]; | ||
65 | string keyRequires = String.Format(@"{0}{1}\{2}\{3}", DependencyCommon.RegistryRoot, requiresKey, DependencyCommon.RegistryDependents, providesKey); | ||
66 | |||
67 | // Get the component ID from the provider. | ||
68 | string componentId = (string)wixDependencyProviderRow[1]; | ||
69 | |||
70 | Row row = this.CreateRegistryRow(wixDependencyRow); | ||
71 | row[0] = this.Core.CreateIdentifier("reg", providesId, requiresId, "(Default)"); | ||
72 | row[1] = -1; | ||
73 | row[2] = keyRequires; | ||
74 | row[3] = "*"; | ||
75 | row[4] = null; | ||
76 | row[5] = componentId; | ||
77 | |||
78 | string minVersion = (string)wixDependencyRow[2]; | ||
79 | if (!String.IsNullOrEmpty(minVersion)) | ||
80 | { | ||
81 | row = this.CreateRegistryRow(wixDependencyRow); | ||
82 | row[0] = this.Core.CreateIdentifier("reg", providesId, requiresId, "MinVersion"); | ||
83 | row[1] = -1; | ||
84 | row[2] = keyRequires; | ||
85 | row[3] = "MinVersion"; | ||
86 | row[4] = minVersion; | ||
87 | row[5] = componentId; | ||
88 | } | ||
89 | |||
90 | string maxVersion = (string)wixDependencyRow[3]; | ||
91 | if (!String.IsNullOrEmpty(minVersion)) | ||
92 | { | ||
93 | row = this.CreateRegistryRow(wixDependencyRow); | ||
94 | row[0] = this.Core.CreateIdentifier("reg", providesId, requiresId, "MaxVersion"); | ||
95 | row[1] = -1; | ||
96 | row[2] = keyRequires; | ||
97 | row[3] = "MaxVersion"; | ||
98 | row[4] = maxVersion; | ||
99 | row[5] = componentId; | ||
100 | } | ||
101 | |||
102 | if (null != wixDependencyRow[4]) | ||
103 | { | ||
104 | int attributes = (int)wixDependencyRow[4]; | ||
105 | |||
106 | row = this.CreateRegistryRow(wixDependencyRow); | ||
107 | row[0] = this.Core.CreateIdentifier("reg", providesId, requiresId, "Attributes"); | ||
108 | row[1] = -1; | ||
109 | row[2] = keyRequires; | ||
110 | row[3] = "Attributes"; | ||
111 | row[4] = String.Concat("#", attributes.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
112 | row[5] = componentId; | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /// <summary> | ||
120 | /// Creates a registry row using source information from the given <see cref="Row"/>. | ||
121 | /// </summary> | ||
122 | /// <param name="referenceRow">The <see cref="Row"/> from which the section and source line information are retrieved.</param> | ||
123 | /// <returns>A new Registry row.</returns> | ||
124 | private Row CreateRegistryRow(Row referenceRow) | ||
125 | { | ||
126 | TableDefinition tableDefinition = this.Core.TableDefinitions["Registry"]; | ||
127 | |||
128 | // Create the row from the main tables, which were populated during link anyway. | ||
129 | // We still associate the table with the dependency row's section to maintain servicing. | ||
130 | Table table = this.output.EnsureTable(tableDefinition, referenceRow.Table.Section); | ||
131 | Row row = table.CreateRow(referenceRow.SourceLineNumbers); | ||
132 | |||
133 | // Set the section ID for patching and return the new row. | ||
134 | row.SectionId = referenceRow.SectionId; | ||
135 | return row; | ||
136 | } | ||
137 | |||
138 | /// <summary> | ||
139 | /// A keyed collection of <see cref="Row"/> instances for O(1) lookup. | ||
140 | /// </summary> | ||
141 | private sealed class KeyedRowCollection : KeyedCollection<string, Row> | ||
142 | { | ||
143 | /// <summary> | ||
144 | /// Initializes the <see cref="KeyedRowCollection"/> class with all rows from the specified <paramref name="table"/>. | ||
145 | /// </summary> | ||
146 | /// <param name="table">The <see cref="Table"/> containing rows to index.</param> | ||
147 | internal KeyedRowCollection(Table table) | ||
148 | { | ||
149 | if (null != table) | ||
150 | { | ||
151 | foreach (Row row in table.Rows) | ||
152 | { | ||
153 | this.Add(row); | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /// <summary> | ||
159 | /// Gets the primary key for the <see cref="Row"/>. | ||
160 | /// </summary> | ||
161 | /// <param name="row">The <see cref="Row"/> to index.</param> | ||
162 | /// <returns>The primary key for the <see cref="Row"/>.</returns> | ||
163 | protected override string GetKeyForItem(Row row) | ||
164 | { | ||
165 | return row.GetPrimaryKey('/'); | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | } | ||
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 @@ | |||
1 | // 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. | ||
2 | |||
3 | namespace WixToolset.Extensions | ||
4 | { | ||
5 | using System; | ||
6 | using WixToolset; | ||
7 | |||
8 | internal static class DependencyCommon | ||
9 | { | ||
10 | // Bundle attributes are in the upper 32-bits. | ||
11 | internal const int ProvidesAttributesBundle = 0x10000; | ||
12 | |||
13 | // Same values as for the Upgrade table in Windows Installer. | ||
14 | internal const int RequiresAttributesMinVersionInclusive = 256; | ||
15 | internal const int RequiresAttributesMaxVersionInclusive = 512; | ||
16 | |||
17 | // The root registry key for the dependency extension. We write to Software\Classes explicitly | ||
18 | // based on the current security context instead of HKCR. See | ||
19 | // http://msdn.microsoft.com/en-us/library/ms724475(VS.85).aspx for more information. | ||
20 | internal static readonly string RegistryRoot = @"Software\Classes\Installer\Dependencies\"; | ||
21 | internal static readonly string RegistryDependents = "Dependents"; | ||
22 | |||
23 | // The following characters cannot be used in a provider key. | ||
24 | internal static readonly char[] InvalidCharacters = new char[] { ' ', '\"', ';', '\\' }; | ||
25 | } | ||
26 | } | ||
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 @@ | |||
1 | // 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. | ||
2 | |||
3 | namespace WixToolset.Extensions | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | ||
8 | using System.Text; | ||
9 | using System.Xml.Linq; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Extensibility; | ||
12 | |||
13 | /// <summary> | ||
14 | /// The compiler for the WiX toolset dependency extension. | ||
15 | /// </summary> | ||
16 | public sealed class DependencyCompiler : CompilerExtension | ||
17 | { | ||
18 | /// <summary> | ||
19 | /// Package type when parsing the Provides element. | ||
20 | /// </summary> | ||
21 | private enum PackageType | ||
22 | { | ||
23 | None, | ||
24 | ExePackage, | ||
25 | MsiPackage, | ||
26 | MspPackage, | ||
27 | MsuPackage | ||
28 | } | ||
29 | |||
30 | public DependencyCompiler() | ||
31 | { | ||
32 | this.Namespace = "http://wixtoolset.org/schemas/v4/wxs/dependency"; | ||
33 | } | ||
34 | |||
35 | /// <summary> | ||
36 | /// Processes an attribute for the Compiler. | ||
37 | /// </summary> | ||
38 | /// <param name="sourceLineNumbers">Source line number for the parent element.</param> | ||
39 | /// <param name="parentElement">Parent element of attribute.</param> | ||
40 | /// <param name="attribute">Attribute to process.</param> | ||
41 | public override void ParseAttribute(XElement parentElement, XAttribute attribute, IDictionary<string, string> context) | ||
42 | { | ||
43 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(parentElement); | ||
44 | switch (parentElement.Name.LocalName) | ||
45 | { | ||
46 | case "Bundle": | ||
47 | switch (attribute.Name.LocalName) | ||
48 | { | ||
49 | case "ProviderKey": | ||
50 | this.ParseProviderKeyAttribute(sourceLineNumbers, parentElement, attribute); | ||
51 | break; | ||
52 | default: | ||
53 | this.Core.UnexpectedAttribute(parentElement, attribute); | ||
54 | break; | ||
55 | } | ||
56 | break; | ||
57 | default: | ||
58 | this.Core.UnexpectedAttribute(parentElement, attribute); | ||
59 | break; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | /// <summary> | ||
64 | /// Processes an element for the Compiler. | ||
65 | /// </summary> | ||
66 | /// <param name="sourceLineNumbers">Source line number for the parent element.</param> | ||
67 | /// <param name="parentElement">Parent element of element to process.</param> | ||
68 | /// <param name="element">Element to process.</param> | ||
69 | /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param> | ||
70 | public override void ParseElement(XElement parentElement, XElement element, IDictionary<string, string> context) | ||
71 | { | ||
72 | PackageType packageType = PackageType.None; | ||
73 | |||
74 | switch (parentElement.Name.LocalName) | ||
75 | { | ||
76 | case "Bundle": | ||
77 | case "Fragment": | ||
78 | case "Module": | ||
79 | case "Product": | ||
80 | switch (element.Name.LocalName) | ||
81 | { | ||
82 | case "Requires": | ||
83 | this.ParseRequiresElement(element, null, false); | ||
84 | break; | ||
85 | default: | ||
86 | this.Core.UnexpectedElement(parentElement, element); | ||
87 | break; | ||
88 | } | ||
89 | break; | ||
90 | case "ExePackage": | ||
91 | packageType = PackageType.ExePackage; | ||
92 | break; | ||
93 | case "MsiPackage": | ||
94 | packageType = PackageType.MsiPackage; | ||
95 | break; | ||
96 | case "MspPackage": | ||
97 | packageType = PackageType.MspPackage; | ||
98 | break; | ||
99 | case "MsuPackage": | ||
100 | packageType = PackageType.MsuPackage; | ||
101 | break; | ||
102 | default: | ||
103 | this.Core.UnexpectedElement(parentElement, element); | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | if (PackageType.None != packageType) | ||
108 | { | ||
109 | string packageId = context["PackageId"]; | ||
110 | |||
111 | switch (element.Name.LocalName) | ||
112 | { | ||
113 | case "Provides": | ||
114 | this.ParseProvidesElement(element, packageType, packageId); | ||
115 | break; | ||
116 | default: | ||
117 | this.Core.UnexpectedElement(parentElement, element); | ||
118 | break; | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /// <summary> | ||
124 | /// Processes a child element of a Component for the Compiler. | ||
125 | /// </summary> | ||
126 | /// <param name="parentElement">Parent element of element to process.</param> | ||
127 | /// <param name="element">Element to process.</param> | ||
128 | /// <param name="context">Extra information about the context in which this element is being parsed.</param> | ||
129 | /// <returns>The component key path type if set.</returns> | ||
130 | public override ComponentKeyPath ParsePossibleKeyPathElement(XElement parentElement, XElement element, IDictionary<string, string> context) | ||
131 | { | ||
132 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(parentElement); | ||
133 | ComponentKeyPath keyPath = null; | ||
134 | |||
135 | switch (parentElement.Name.LocalName) | ||
136 | { | ||
137 | case "Component": | ||
138 | string componentId = context["ComponentId"]; | ||
139 | |||
140 | // 64-bit components may cause issues downlevel. | ||
141 | bool win64 = false; | ||
142 | Boolean.TryParse(context["Win64"], out win64); | ||
143 | |||
144 | switch (element.Name.LocalName) | ||
145 | { | ||
146 | case "Provides": | ||
147 | if (win64) | ||
148 | { | ||
149 | this.Core.OnMessage(DependencyWarnings.Win64Component(sourceLineNumbers, componentId)); | ||
150 | } | ||
151 | |||
152 | keyPath = this.ParseProvidesElement(element, PackageType.None, componentId); | ||
153 | break; | ||
154 | default: | ||
155 | this.Core.UnexpectedElement(parentElement, element); | ||
156 | break; | ||
157 | } | ||
158 | break; | ||
159 | default: | ||
160 | this.Core.UnexpectedElement(parentElement, element); | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | return keyPath; | ||
165 | } | ||
166 | |||
167 | /// <summary> | ||
168 | /// Processes the ProviderKey bundle attribute. | ||
169 | /// </summary> | ||
170 | /// <param name="sourceLineNumbers">Source line number for the parent element.</param> | ||
171 | /// <param name="parentElement">Parent element of attribute.</param> | ||
172 | /// <param name="attribute">The XML attribute for the ProviderKey attribute.</param> | ||
173 | private void ParseProviderKeyAttribute(SourceLineNumber sourceLineNumbers, XElement parentElement, XAttribute attribute) | ||
174 | { | ||
175 | Identifier id = null; | ||
176 | string providerKey = null; | ||
177 | int illegalChar = -1; | ||
178 | |||
179 | switch (attribute.Name.LocalName) | ||
180 | { | ||
181 | case "ProviderKey": | ||
182 | providerKey = this.Core.GetAttributeValue(sourceLineNumbers, attribute); | ||
183 | break; | ||
184 | default: | ||
185 | this.Core.UnexpectedAttribute(parentElement, attribute); | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | // Make sure the key does not contain any illegal characters or values. | ||
190 | if (String.IsNullOrEmpty(providerKey)) | ||
191 | { | ||
192 | this.Core.OnMessage(WixErrors.IllegalEmptyAttributeValue(sourceLineNumbers, parentElement.Name.LocalName, attribute.Name.LocalName)); | ||
193 | } | ||
194 | else if (0 <= (illegalChar = providerKey.IndexOfAny(DependencyCommon.InvalidCharacters))) | ||
195 | { | ||
196 | StringBuilder sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2); | ||
197 | Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" ")); | ||
198 | |||
199 | this.Core.OnMessage(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "ProviderKey", providerKey[illegalChar], sb.ToString())); | ||
200 | } | ||
201 | else if ("ALL" == providerKey) | ||
202 | { | ||
203 | this.Core.OnMessage(DependencyErrors.ReservedValue(sourceLineNumbers, parentElement.Name.LocalName, "ProviderKey", providerKey)); | ||
204 | } | ||
205 | |||
206 | // Generate the primary key for the row. | ||
207 | id = this.Core.CreateIdentifier("dep", attribute.Name.LocalName, providerKey); | ||
208 | |||
209 | if (!this.Core.EncounteredError) | ||
210 | { | ||
211 | // Create the provider row for the bundle. The Component_ field is required | ||
212 | // in the table definition but unused for bundles, so just set it to the valid ID. | ||
213 | Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyProvider", id); | ||
214 | row[1] = id.Id; | ||
215 | row[2] = providerKey; | ||
216 | row[5] = DependencyCommon.ProvidesAttributesBundle; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | /// <summary> | ||
221 | /// Processes the Provides element. | ||
222 | /// </summary> | ||
223 | /// <param name="node">The XML node for the Provides element.</param> | ||
224 | /// <param name="packageType">The type of the package being chained into a bundle, or "None" if building an MSI package.</param> | ||
225 | /// <param name="keyPath">Explicit key path.</param> | ||
226 | /// <param name="parentId">The identifier of the parent component or package.</param> | ||
227 | /// <returns>The type of key path if set.</returns> | ||
228 | private ComponentKeyPath ParseProvidesElement(XElement node, PackageType packageType, string parentId) | ||
229 | { | ||
230 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
231 | ComponentKeyPath keyPath = null; | ||
232 | Identifier id = null; | ||
233 | string key = null; | ||
234 | string version = null; | ||
235 | string displayName = null; | ||
236 | int attributes = 0; | ||
237 | int illegalChar = -1; | ||
238 | |||
239 | foreach (XAttribute attrib in node.Attributes()) | ||
240 | { | ||
241 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | ||
242 | { | ||
243 | switch (attrib.Name.LocalName) | ||
244 | { | ||
245 | case "Id": | ||
246 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
247 | break; | ||
248 | case "Key": | ||
249 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
250 | break; | ||
251 | case "Version": | ||
252 | version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
253 | break; | ||
254 | case "DisplayName": | ||
255 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
256 | break; | ||
257 | default: | ||
258 | this.Core.UnexpectedAttribute(node, attrib); | ||
259 | break; | ||
260 | } | ||
261 | } | ||
262 | else | ||
263 | { | ||
264 | this.Core.ParseExtensionAttribute(node, attrib); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | // Make sure the key is valid. The key will default to the ProductCode for MSI packages | ||
269 | // and the package code for MSP packages in the binder if not specified. | ||
270 | if (!String.IsNullOrEmpty(key)) | ||
271 | { | ||
272 | // Make sure the key does not contain any illegal characters or values. | ||
273 | if (0 <= (illegalChar = key.IndexOfAny(DependencyCommon.InvalidCharacters))) | ||
274 | { | ||
275 | StringBuilder sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2); | ||
276 | Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" ")); | ||
277 | |||
278 | this.Core.OnMessage(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "Key", key[illegalChar], sb.ToString())); | ||
279 | } | ||
280 | else if ("ALL" == key) | ||
281 | { | ||
282 | this.Core.OnMessage(DependencyErrors.ReservedValue(sourceLineNumbers, node.Name.LocalName, "Key", key)); | ||
283 | } | ||
284 | } | ||
285 | else if (PackageType.ExePackage == packageType || PackageType.MsuPackage == packageType) | ||
286 | { | ||
287 | // Must specify the provider key when authored for a package. | ||
288 | this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
289 | } | ||
290 | else if (PackageType.None == packageType) | ||
291 | { | ||
292 | // Make sure the ProductCode is authored and set the key. | ||
293 | this.Core.CreateSimpleReference(sourceLineNumbers, "Property", "ProductCode"); | ||
294 | key = "!(bind.property.ProductCode)"; | ||
295 | } | ||
296 | |||
297 | // The Version attribute should not be authored in or for an MSI package. | ||
298 | if (!String.IsNullOrEmpty(version)) | ||
299 | { | ||
300 | switch (packageType) | ||
301 | { | ||
302 | case PackageType.None: | ||
303 | this.Core.OnMessage(DependencyWarnings.DiscouragedVersionAttribute(sourceLineNumbers)); | ||
304 | break; | ||
305 | case PackageType.MsiPackage: | ||
306 | this.Core.OnMessage(DependencyWarnings.DiscouragedVersionAttribute(sourceLineNumbers, parentId)); | ||
307 | break; | ||
308 | } | ||
309 | } | ||
310 | else if (PackageType.MspPackage == packageType || PackageType.MsuPackage == packageType) | ||
311 | { | ||
312 | // Must specify the Version when authored for packages that do not contain a version. | ||
313 | this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
314 | } | ||
315 | |||
316 | // Need the element ID for child element processing, so generate now if not authored. | ||
317 | if (null == id) | ||
318 | { | ||
319 | id = this.Core.CreateIdentifier("dep", node.Name.LocalName, parentId, key); | ||
320 | } | ||
321 | |||
322 | foreach (XElement child in node.Elements()) | ||
323 | { | ||
324 | if (this.Namespace == child.Name.Namespace) | ||
325 | { | ||
326 | switch (child.Name.LocalName) | ||
327 | { | ||
328 | case "Requires": | ||
329 | this.ParseRequiresElement(child, id.Id, PackageType.None == packageType); | ||
330 | break; | ||
331 | case "RequiresRef": | ||
332 | this.ParseRequiresRefElement(child, id.Id, PackageType.None == packageType); | ||
333 | break; | ||
334 | default: | ||
335 | this.Core.UnexpectedElement(node, child); | ||
336 | break; | ||
337 | } | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | this.Core.ParseExtensionElement(node, child); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | if (!this.Core.EncounteredError) | ||
346 | { | ||
347 | // Create the row in the provider table. | ||
348 | Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyProvider", id); | ||
349 | row[1] = parentId; | ||
350 | row[2] = key; | ||
351 | |||
352 | if (!String.IsNullOrEmpty(version)) | ||
353 | { | ||
354 | row[3] = version; | ||
355 | } | ||
356 | |||
357 | if (!String.IsNullOrEmpty(displayName)) | ||
358 | { | ||
359 | row[4] = displayName; | ||
360 | } | ||
361 | |||
362 | if (0 != attributes) | ||
363 | { | ||
364 | row[5] = attributes; | ||
365 | } | ||
366 | |||
367 | if (PackageType.None == packageType) | ||
368 | { | ||
369 | // Reference the Check custom action to check for dependencies on the current provider. | ||
370 | if (Platform.ARM == this.Core.CurrentPlatform) | ||
371 | { | ||
372 | // Ensure the ARM version of the CA is referenced. | ||
373 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyCheck_ARM"); | ||
374 | } | ||
375 | else | ||
376 | { | ||
377 | // All other supported platforms use x86. | ||
378 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyCheck"); | ||
379 | } | ||
380 | |||
381 | // Generate registry rows for the provider using binder properties. | ||
382 | string keyProvides = String.Concat(DependencyCommon.RegistryRoot, key); | ||
383 | |||
384 | row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "(Default)")); | ||
385 | row[1] = -1; | ||
386 | row[2] = keyProvides; | ||
387 | row[3] = null; | ||
388 | row[4] = "[ProductCode]"; | ||
389 | row[5] = parentId; | ||
390 | |||
391 | // Use the Version registry value and use that as a potential key path. | ||
392 | Identifier idVersion = this.Core.CreateIdentifier("reg", id.Id, "Version"); | ||
393 | keyPath = new ComponentKeyPath() { Id = idVersion.Id, Explicit = false, Type = ComponentKeyPathType.Registry }; | ||
394 | |||
395 | row = this.Core.CreateRow(sourceLineNumbers, "Registry", idVersion); | ||
396 | row[1] = -1; | ||
397 | row[2] = keyProvides; | ||
398 | row[3] = "Version"; | ||
399 | row[4] = !String.IsNullOrEmpty(version) ? version : "[ProductVersion]"; | ||
400 | row[5] = parentId; | ||
401 | |||
402 | row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "DisplayName")); | ||
403 | row[1] = -1; | ||
404 | row[2] = keyProvides; | ||
405 | row[3] = "DisplayName"; | ||
406 | row[4] = !String.IsNullOrEmpty(displayName) ? displayName : "[ProductName]"; | ||
407 | row[5] = parentId; | ||
408 | |||
409 | if (0 != attributes) | ||
410 | { | ||
411 | row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "Attributes")); | ||
412 | row[1] = -1; | ||
413 | row[2] = keyProvides; | ||
414 | row[3] = "Attributes"; | ||
415 | row[4] = String.Concat("#", attributes.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
416 | row[5] = parentId; | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | |||
421 | return keyPath; | ||
422 | } | ||
423 | |||
424 | /// <summary> | ||
425 | /// Processes the Requires element. | ||
426 | /// </summary> | ||
427 | /// <param name="node">The XML node for the Requires element.</param> | ||
428 | /// <param name="providerId">The parent provider identifier.</param> | ||
429 | /// <param name="requiresAction">Whether the Requires custom action should be referenced.</param> | ||
430 | private void ParseRequiresElement(XElement node, string providerId, bool requiresAction) | ||
431 | { | ||
432 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
433 | Identifier id = null; | ||
434 | string providerKey = null; | ||
435 | string minVersion = null; | ||
436 | string maxVersion = null; | ||
437 | int attributes = 0; | ||
438 | int illegalChar = -1; | ||
439 | |||
440 | foreach (XAttribute attrib in node.Attributes()) | ||
441 | { | ||
442 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | ||
443 | { | ||
444 | switch (attrib.Name.LocalName) | ||
445 | { | ||
446 | case "Id": | ||
447 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
448 | break; | ||
449 | case "ProviderKey": | ||
450 | providerKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
451 | break; | ||
452 | case "Minimum": | ||
453 | minVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
454 | break; | ||
455 | case "Maximum": | ||
456 | maxVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
457 | break; | ||
458 | case "IncludeMinimum": | ||
459 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
460 | { | ||
461 | attributes |= DependencyCommon.RequiresAttributesMinVersionInclusive; | ||
462 | } | ||
463 | break; | ||
464 | case "IncludeMaximum": | ||
465 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
466 | { | ||
467 | attributes |= DependencyCommon.RequiresAttributesMaxVersionInclusive; | ||
468 | } | ||
469 | break; | ||
470 | default: | ||
471 | this.Core.UnexpectedAttribute(node, attrib); | ||
472 | break; | ||
473 | } | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | this.Core.ParseExtensionAttribute(node, attrib); | ||
478 | } | ||
479 | } | ||
480 | |||
481 | this.Core.ParseForExtensionElements(node); | ||
482 | |||
483 | if (null == id) | ||
484 | { | ||
485 | // Generate an ID only if this element is authored under a Provides element; otherwise, a RequiresRef | ||
486 | // element will be necessary and the Id attribute will be required. | ||
487 | if (!String.IsNullOrEmpty(providerId)) | ||
488 | { | ||
489 | id = this.Core.CreateIdentifier("dep", node.Name.LocalName, providerKey); | ||
490 | } | ||
491 | else | ||
492 | { | ||
493 | this.Core.OnMessage(WixErrors.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Id", "Provides")); | ||
494 | id = Identifier.Invalid; | ||
495 | } | ||
496 | } | ||
497 | |||
498 | if (String.IsNullOrEmpty(providerKey)) | ||
499 | { | ||
500 | this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProviderKey")); | ||
501 | } | ||
502 | // Make sure the key does not contain any illegal characters. | ||
503 | else if (0 <= (illegalChar = providerKey.IndexOfAny(DependencyCommon.InvalidCharacters))) | ||
504 | { | ||
505 | StringBuilder sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2); | ||
506 | Array.ForEach<char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" ")); | ||
507 | |||
508 | this.Core.OnMessage(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "ProviderKey", providerKey[illegalChar], sb.ToString())); | ||
509 | } | ||
510 | |||
511 | |||
512 | if (!this.Core.EncounteredError) | ||
513 | { | ||
514 | // Reference the Require custom action if required. | ||
515 | if (requiresAction) | ||
516 | { | ||
517 | if (Platform.ARM == this.Core.CurrentPlatform) | ||
518 | { | ||
519 | // Ensure the ARM version of the CA is referenced. | ||
520 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire_ARM"); | ||
521 | } | ||
522 | else | ||
523 | { | ||
524 | // All other supported platforms use x86. | ||
525 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire"); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependency", id); | ||
530 | row[1] = providerKey; | ||
531 | row[2] = minVersion; | ||
532 | row[3] = maxVersion; | ||
533 | |||
534 | if (0 != attributes) | ||
535 | { | ||
536 | row[4] = attributes; | ||
537 | } | ||
538 | |||
539 | // Create the relationship between this WixDependency row and the WixDependencyProvider row. | ||
540 | if (!String.IsNullOrEmpty(providerId)) | ||
541 | { | ||
542 | // Create the relationship between the WixDependency row and the parent WixDependencyProvider row. | ||
543 | row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyRef"); | ||
544 | row[0] = providerId; | ||
545 | row[1] = id.Id; | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /// <summary> | ||
551 | /// Processes the RequiresRef element. | ||
552 | /// </summary> | ||
553 | /// <param name="node">The XML node for the RequiresRef element.</param> | ||
554 | /// <param name="providerId">The parent provider identifier.</param> | ||
555 | /// <param name="requiresAction">Whether the Requires custom action should be referenced.</param> | ||
556 | private void ParseRequiresRefElement(XElement node, string providerId, bool requiresAction) | ||
557 | { | ||
558 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
559 | string id = null; | ||
560 | |||
561 | foreach (XAttribute attrib in node.Attributes()) | ||
562 | { | ||
563 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | ||
564 | { | ||
565 | switch (attrib.Name.LocalName) | ||
566 | { | ||
567 | case "Id": | ||
568 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
569 | break; | ||
570 | default: | ||
571 | this.Core.UnexpectedAttribute(node, attrib); | ||
572 | break; | ||
573 | } | ||
574 | } | ||
575 | else | ||
576 | { | ||
577 | this.Core.ParseExtensionAttribute(node, attrib); | ||
578 | } | ||
579 | } | ||
580 | |||
581 | this.Core.ParseForExtensionElements(node); | ||
582 | |||
583 | if (String.IsNullOrEmpty(id)) | ||
584 | { | ||
585 | this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
586 | } | ||
587 | |||
588 | if (!this.Core.EncounteredError) | ||
589 | { | ||
590 | // Reference the Require custom action if required. | ||
591 | if (requiresAction) | ||
592 | { | ||
593 | if (Platform.ARM == this.Core.CurrentPlatform) | ||
594 | { | ||
595 | // Ensure the ARM version of the CA is referenced. | ||
596 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire_ARM"); | ||
597 | } | ||
598 | else | ||
599 | { | ||
600 | // All other supported platforms use x86. | ||
601 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire"); | ||
602 | } | ||
603 | } | ||
604 | |||
605 | // Create a link dependency on the row that contains information we'll need during bind. | ||
606 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixDependency", id); | ||
607 | |||
608 | // Create the relationship between the WixDependency row and the parent WixDependencyProvider row. | ||
609 | Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyRef"); | ||
610 | row[0] = providerId; | ||
611 | row[1] = id; | ||
612 | } | ||
613 | } | ||
614 | } | ||
615 | } | ||
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 @@ | |||
1 | // 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. | ||
2 | |||
3 | namespace WixToolset.Extensions | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Collections.ObjectModel; | ||
8 | using WixToolset; | ||
9 | using WixToolset.Data; | ||
10 | using WixToolset.Extensibility; | ||
11 | using WixToolset.Extensions.Serialize.Dependency; | ||
12 | using Dependency = WixToolset.Extensions.Serialize.Dependency; | ||
13 | using Wix = WixToolset.Data.Serialize; | ||
14 | |||
15 | /// <summary> | ||
16 | /// The decompiler for the WiX toolset dependency extension. | ||
17 | /// </summary> | ||
18 | public sealed class DependencyDecompiler : DecompilerExtension | ||
19 | { | ||
20 | private RegistryKeyValueCollection registryValues; | ||
21 | private Dictionary<string, string> keyCache; | ||
22 | |||
23 | /// <summary> | ||
24 | /// Creates a new instance of the <see cref="DependencyDecompiler"/> class. | ||
25 | /// </summary> | ||
26 | public DependencyDecompiler() | ||
27 | { | ||
28 | this.registryValues = new RegistryKeyValueCollection(); | ||
29 | this.keyCache = new Dictionary<string, string>(); | ||
30 | |||
31 | this.TableDefinitions = DependencyExtensionData.GetExtensionTableDefinitions(); | ||
32 | } | ||
33 | |||
34 | /// <summary> | ||
35 | /// Get the extensions library to be removed. | ||
36 | /// </summary> | ||
37 | /// <param name="tableDefinitions">Table definitions for library.</param> | ||
38 | /// <returns>Library to remove from decompiled output.</returns> | ||
39 | public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions) | ||
40 | { | ||
41 | return DependencyExtensionData.GetExtensionLibrary(tableDefinitions); | ||
42 | } | ||
43 | |||
44 | /// <summary> | ||
45 | /// Decompiles an extension table. | ||
46 | /// </summary> | ||
47 | /// <param name="table">The table to decompile.</param> | ||
48 | public override void DecompileTable(Table table) | ||
49 | { | ||
50 | switch (table.Name) | ||
51 | { | ||
52 | case "WixDependencyProvider": | ||
53 | this.DecompileWixDependencyProviderTable(table); | ||
54 | break; | ||
55 | |||
56 | case "WixDependency": | ||
57 | this.DecompileWixDependencyTable(table); | ||
58 | break; | ||
59 | |||
60 | case "WixDependencyRef": | ||
61 | this.DecompileWixDependencyRefTable(table); | ||
62 | break; | ||
63 | |||
64 | default: | ||
65 | base.DecompileTable(table); | ||
66 | break; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | /// <summary> | ||
71 | /// Finalize decompilation by removing registry values that the compiler writes. | ||
72 | /// </summary> | ||
73 | /// <param name="tables">The collection of all tables.</param> | ||
74 | public override void Finish(TableIndexedCollection tables) | ||
75 | { | ||
76 | // Remove generated registry rows. | ||
77 | this.FinalizeRegistryTable(tables); | ||
78 | |||
79 | // Remove extension properties. | ||
80 | this.FinalizeProperties(); | ||
81 | } | ||
82 | |||
83 | /// <summary> | ||
84 | /// Decompiles the WixDependencyProvider table. | ||
85 | /// </summary> | ||
86 | /// <param name="table">The table to decompile.</param> | ||
87 | private void DecompileWixDependencyProviderTable(Table table) | ||
88 | { | ||
89 | foreach (Row row in table.Rows) | ||
90 | { | ||
91 | Provides provides = new Provides(); | ||
92 | |||
93 | provides.Id = (string)row[0]; | ||
94 | provides.Key = (string)row[2]; | ||
95 | |||
96 | if (null != row[3]) | ||
97 | { | ||
98 | provides.Version = (string)row[3]; | ||
99 | } | ||
100 | |||
101 | if (null != row[4]) | ||
102 | { | ||
103 | provides.DisplayName = (string)row[4]; | ||
104 | } | ||
105 | |||
106 | // Nothing to parse for attributes currently. | ||
107 | |||
108 | Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); | ||
109 | if (null != component) | ||
110 | { | ||
111 | component.AddChild(provides); | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); | ||
116 | } | ||
117 | |||
118 | // Index the provider to parent the RequiresRef elements. | ||
119 | this.Core.IndexElement(row, provides); | ||
120 | |||
121 | // Add the provider-specific registry keys to be removed during finalization. | ||
122 | // Only remove specific keys that the compiler writes. | ||
123 | string keyProvides = String.Concat(DependencyCommon.RegistryRoot, provides.Key); | ||
124 | |||
125 | this.registryValues.Add(keyProvides, null); | ||
126 | this.registryValues.Add(keyProvides, "Version"); | ||
127 | this.registryValues.Add(keyProvides, "DisplayName"); | ||
128 | this.registryValues.Add(keyProvides, "Attributes"); | ||
129 | |||
130 | // Cache the provider key. | ||
131 | this.keyCache[provides.Id] = provides.Key; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | /// <summary> | ||
136 | /// Decompiles the WixDependency table. | ||
137 | /// </summary> | ||
138 | /// <param name="table">The table to decompile.</param> | ||
139 | private void DecompileWixDependencyTable(Table table) | ||
140 | { | ||
141 | foreach (Row row in table.Rows) | ||
142 | { | ||
143 | Requires requires = new Requires(); | ||
144 | |||
145 | requires.Id = (string)row[0]; | ||
146 | requires.ProviderKey = (string)row[1]; | ||
147 | |||
148 | if (null != row[2]) | ||
149 | { | ||
150 | requires.Minimum = (string)row[2]; | ||
151 | } | ||
152 | |||
153 | if (null != row[3]) | ||
154 | { | ||
155 | requires.Maximum = (string)row[3]; | ||
156 | } | ||
157 | |||
158 | if (null != row[4]) | ||
159 | { | ||
160 | int attributes = (int)row[4]; | ||
161 | |||
162 | if (0 != (attributes & DependencyCommon.RequiresAttributesMinVersionInclusive)) | ||
163 | { | ||
164 | requires.IncludeMinimum = Dependency.YesNoType.yes; | ||
165 | } | ||
166 | |||
167 | if (0 != (attributes & DependencyCommon.RequiresAttributesMaxVersionInclusive)) | ||
168 | { | ||
169 | requires.IncludeMaximum = Dependency.YesNoType.yes; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | this.Core.RootElement.AddChild(requires); | ||
174 | |||
175 | // Cache the requires key. | ||
176 | this.keyCache[requires.Id] = requires.ProviderKey; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /// <summary> | ||
181 | /// Decompiles the WixDependencyRef table. | ||
182 | /// </summary> | ||
183 | /// <param name="table">The table to decompile.</param> | ||
184 | private void DecompileWixDependencyRefTable(Table table) | ||
185 | { | ||
186 | foreach (Row row in table.Rows) | ||
187 | { | ||
188 | RequiresRef requiresRef = new RequiresRef(); | ||
189 | |||
190 | requiresRef.Id = (string)row[1]; | ||
191 | |||
192 | Provides provides = (Provides)this.Core.GetIndexedElement("WixDependencyProvider", (string)row[0]); | ||
193 | if (null != provides) | ||
194 | { | ||
195 | provides.AddChild(requiresRef); | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "WixDependencyProvider_", (string)row[0], "WixDependencyProvider")); | ||
200 | } | ||
201 | |||
202 | // Get the cached keys for the provider and dependency IDs and generate registry rows. | ||
203 | string providesKey = null; | ||
204 | string requiresKey = null; | ||
205 | |||
206 | if (null != provides && this.keyCache.ContainsKey(provides.Id)) | ||
207 | { | ||
208 | providesKey = this.keyCache[provides.Id]; | ||
209 | } | ||
210 | else | ||
211 | { | ||
212 | this.Core.OnMessage(DependencyWarnings.ProvidesKeyNotFound(row.SourceLineNumbers, provides.Id)); | ||
213 | } | ||
214 | |||
215 | if (this.keyCache.ContainsKey(requiresRef.Id)) | ||
216 | { | ||
217 | requiresKey = this.keyCache[requiresRef.Id]; | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | this.Core.OnMessage(DependencyWarnings.RequiresKeyNotFound(row.SourceLineNumbers, requiresRef.Id)); | ||
222 | } | ||
223 | |||
224 | if (!this.Core.EncounteredError) | ||
225 | { | ||
226 | // Add the dependency-specific registry keys to be removed during finalization. | ||
227 | // Only remove specific keys that the compiler writes. | ||
228 | string keyRequires = String.Format(@"{0}{1}\{2}\{3}", DependencyCommon.RegistryRoot, requiresKey, DependencyCommon.RegistryDependents, providesKey); | ||
229 | |||
230 | this.registryValues.Add(keyRequires, "*"); | ||
231 | this.registryValues.Add(keyRequires, "MinVersion"); | ||
232 | this.registryValues.Add(keyRequires, "MaxVersion"); | ||
233 | this.registryValues.Add(keyRequires, "Attributes"); | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | |||
238 | /// <summary> | ||
239 | /// Removes rows from the Registry table that are generated by this extension. | ||
240 | /// </summary> | ||
241 | /// <param name="tables">The collection of tables.</param> | ||
242 | private void FinalizeRegistryTable(TableIndexedCollection tables) | ||
243 | { | ||
244 | Table registryTable = tables["Registry"]; | ||
245 | if (null != registryTable) | ||
246 | { | ||
247 | foreach (Row registryRow in registryTable.Rows) | ||
248 | { | ||
249 | // Check if the compiler writes this registry value; if so, it should be removed. | ||
250 | if (this.registryValues.Contains(registryRow)) | ||
251 | { | ||
252 | Wix.ISchemaElement elem = this.Core.GetIndexedElement(registryRow); | ||
253 | |||
254 | // If the registry row was found, remove it from its parent. | ||
255 | if (null != elem && null != elem.ParentElement) | ||
256 | { | ||
257 | Wix.IParentElement elemParent = elem.ParentElement as Wix.IParentElement; | ||
258 | if (null != elemParent) | ||
259 | { | ||
260 | elemParent.RemoveChild(elem); | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /// <summary> | ||
269 | /// Removes properties defined by this extension. | ||
270 | /// </summary> | ||
271 | /// <param name="tables">The collection of tables.</param> | ||
272 | private void FinalizeProperties() | ||
273 | { | ||
274 | string[] properties = new string[] { "DISABLEDEPENDENCYCHECK", "IGNOREDEPENDENCIES" }; | ||
275 | foreach (string property in properties) | ||
276 | { | ||
277 | Wix.Property elem = this.Core.GetIndexedElement("Property", property) as Wix.Property; | ||
278 | if (null != elem) | ||
279 | { | ||
280 | // If a value is defined, log a warning we're removing it. | ||
281 | if (!String.IsNullOrEmpty(elem.Value)) | ||
282 | { | ||
283 | this.Core.OnMessage(DependencyWarnings.PropertyRemoved(elem.Id)); | ||
284 | } | ||
285 | |||
286 | // If the property row was found, remove it from its parent. | ||
287 | if (null != elem.ParentElement) | ||
288 | { | ||
289 | Wix.IParentElement elemParent = elem.ParentElement as Wix.IParentElement; | ||
290 | if (null != elemParent) | ||
291 | { | ||
292 | elemParent.RemoveChild(elem); | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | } | ||
297 | } | ||
298 | |||
299 | /// <summary> | ||
300 | /// Provides an O(1) lookup for registry key and value name pairs for use in the decompiler. | ||
301 | /// </summary> | ||
302 | private sealed class RegistryKeyValueCollection : KeyedCollection<int, KeyValuePair<string, string>> | ||
303 | { | ||
304 | /// <summary> | ||
305 | /// Adds the registry key and value name pair to the collection if it doesn't already exist. | ||
306 | /// </summary> | ||
307 | /// <param name="key">The registry key to add.</param> | ||
308 | /// <param name="name">The registry value name to add.</param> | ||
309 | internal void Add(string key, string name) | ||
310 | { | ||
311 | KeyValuePair<string, string> pair = new KeyValuePair<string, string>(key, name); | ||
312 | if (!this.Contains(pair)) | ||
313 | { | ||
314 | this.Add(pair); | ||
315 | } | ||
316 | } | ||
317 | |||
318 | /// <summary> | ||
319 | /// Returns whether the collection contains the registry key and value name pair from the <see cref="Row"/>. | ||
320 | /// </summary> | ||
321 | /// <param name="row">The registry <see cref="Row"/> to search for.</param> | ||
322 | /// <returns>True if the collection contains the registry key and value name pair from the <see cref="Row"/>; otherwise, false.</returns> | ||
323 | internal bool Contains(Row row) | ||
324 | { | ||
325 | if (null == row) | ||
326 | { | ||
327 | return false; | ||
328 | } | ||
329 | |||
330 | KeyValuePair<string, string> pair = new KeyValuePair<string, string>((string)row[2], (string)row[3]); | ||
331 | return this.Contains(pair); | ||
332 | } | ||
333 | |||
334 | /// <summary> | ||
335 | /// Return the hash code of the key and value pair concatenated with a colon as a delimiter. | ||
336 | /// </summary> | ||
337 | /// <param name="pair">The registry key and value name pair.</param> | ||
338 | /// <returns></returns> | ||
339 | protected override int GetKeyForItem(KeyValuePair<string, string> pair) | ||
340 | { | ||
341 | return String.Concat(pair.Key, ":", pair.Value).GetHashCode(); | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | } | ||
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 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | |||
5 | <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> | ||
6 | <PropertyGroup> | ||
7 | <ProjectGuid>{A0B6D3F1-AE5E-423B-BA92-60C9926CA498}</ProjectGuid> | ||
8 | <AssemblyName>WixDependencyExtension</AssemblyName> | ||
9 | <OutputType>Library</OutputType> | ||
10 | <RootNamespace>WixToolset.Extensions</RootNamespace> | ||
11 | </PropertyGroup> | ||
12 | <ItemGroup> | ||
13 | <Compile Include="AssemblyInfo.cs" /> | ||
14 | <Compile Include="DependencyBinder.cs" /> | ||
15 | <Compile Include="DependencyCommon.cs" /> | ||
16 | <Compile Include="DependencyCompiler.cs" /> | ||
17 | <Compile Include="DependencyDecompiler.cs" /> | ||
18 | <Compile Include="DependencyExtensionData.cs" /> | ||
19 | <EmbeddedFlattenedResource Include="Data\tables.xml"> | ||
20 | <LogicalName>$(RootNamespace).Data.tables.xml</LogicalName> | ||
21 | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
22 | </EmbeddedFlattenedResource> | ||
23 | <MsgGenSource Include="Data\messages.xml"> | ||
24 | <ResourcesLogicalName>$(RootNamespace).Data.Messages.resources</ResourcesLogicalName> | ||
25 | </MsgGenSource> | ||
26 | <EmbeddedFlattenedResource Include="Xsd\Dependency.xsd"> | ||
27 | <LogicalName>$(RootNamespace).Xsd.Dependency.xsd</LogicalName> | ||
28 | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
29 | </EmbeddedFlattenedResource> | ||
30 | <XsdGenSource Include="Xsd\Dependency.xsd"> | ||
31 | <CommonNamespace>WixToolset.Data.Serialize</CommonNamespace> | ||
32 | <Namespace>WixToolset.Extensions.Serialize.Dependency</Namespace> | ||
33 | </XsdGenSource> | ||
34 | <EmbeddedResource Include="$(OutputPath)Dependency.wixlib"> | ||
35 | <Link>Data\Dependency.wixlib</Link> | ||
36 | </EmbeddedResource> | ||
37 | </ItemGroup> | ||
38 | <ItemGroup> | ||
39 | <Reference Include="System" /> | ||
40 | <Reference Include="System.Xml" /> | ||
41 | <Reference Include="System.Xml.Linq" /> | ||
42 | <ProjectReference Include="..\..\..\libs\WixToolset.Data\WixToolset.Data.csproj" /> | ||
43 | <ProjectReference Include="..\..\..\libs\WixToolset.Extensibility\WixToolset.Extensibility.csproj" /> | ||
44 | <ProjectReference Include="..\..\..\tools\wix\Wix.csproj" /> | ||
45 | <ProjectReference Include="..\wixlib\DependencyExtension.wixproj"> | ||
46 | <ReferenceOutputAssembly>false</ReferenceOutputAssembly> | ||
47 | </ProjectReference> | ||
48 | </ItemGroup> | ||
49 | <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" /> | ||
50 | </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 @@ | |||
1 | // 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. | ||
2 | |||
3 | namespace WixToolset.Extensions | ||
4 | { | ||
5 | using System; | ||
6 | using System.Reflection; | ||
7 | using WixToolset.Data; | ||
8 | using WixToolset.Extensibility; | ||
9 | |||
10 | /// <summary> | ||
11 | /// The WiX toolset dependency extension. | ||
12 | /// </summary> | ||
13 | public sealed class DependencyExtensionData : ExtensionData | ||
14 | { | ||
15 | /// <summary> | ||
16 | /// Gets the default culture. | ||
17 | /// </summary> | ||
18 | /// <value>The default culture.</value> | ||
19 | public override string DefaultCulture | ||
20 | { | ||
21 | get { return "en-us"; } | ||
22 | } | ||
23 | |||
24 | /// <summary> | ||
25 | /// Gets the optional table definitions for this extension. | ||
26 | /// </summary> | ||
27 | /// <value>The optional table definitions for this extension.</value> | ||
28 | public override TableDefinitionCollection TableDefinitions | ||
29 | { | ||
30 | get | ||
31 | { | ||
32 | return DependencyExtensionData.GetExtensionTableDefinitions(); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | /// <summary> | ||
37 | /// Gets the library associated with this extension. | ||
38 | /// </summary> | ||
39 | /// <param name="tableDefinitions">The table definitions to use while loading the library.</param> | ||
40 | /// <returns>The loaded library.</returns> | ||
41 | public override Library GetLibrary(TableDefinitionCollection tableDefinitions) | ||
42 | { | ||
43 | return DependencyExtensionData.GetExtensionLibrary(tableDefinitions); | ||
44 | } | ||
45 | |||
46 | /// <summary> | ||
47 | /// Internal mechanism to access the extension's table definitions. | ||
48 | /// </summary> | ||
49 | /// <returns>Extension's table definitions.</returns> | ||
50 | internal static TableDefinitionCollection GetExtensionTableDefinitions() | ||
51 | { | ||
52 | return ExtensionData.LoadTableDefinitionHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.tables.xml"); | ||
53 | } | ||
54 | |||
55 | /// <summary> | ||
56 | /// Internal mechanism to access the extension's library. | ||
57 | /// </summary> | ||
58 | /// <returns>Extension's library.</returns> | ||
59 | internal static Library GetExtensionLibrary(TableDefinitionCollection tableDefinitions) | ||
60 | { | ||
61 | return ExtensionData.LoadLibraryHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.Dependency.wixlib", tableDefinitions); | ||
62 | } | ||
63 | } | ||
64 | } | ||
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 @@ | |||
1 | <?xml version='1.0' encoding='utf-8'?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | |||
5 | <Messages Namespace="WixToolset.Extensions" Resources="Data.Messages" xmlns="http://schemas.microsoft.com/genmsgs/2004/07/messages"> | ||
6 | <Class Name="DependencyErrors" ContainerName="DependencyErrorEventArgs" BaseContainerName="MessageEventArgs"> | ||
7 | <Message Id="IllegalCharactersInProvider" Number="5400"> | ||
8 | <Instance> | ||
9 | 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} | ||
10 | <Parameter Type="System.String" Name="attributeName" /> | ||
11 | <Parameter Type="System.Char" Name="illegalChar" /> | ||
12 | <Parameter Type="System.String" Name="illegalChars" /> | ||
13 | </Instance> | ||
14 | </Message> | ||
15 | <Message Id="ReservedValue" Number="5401"> | ||
16 | <Instance> | ||
17 | The {0}/@{1} attribute value '{2}' is reserved and cannot be used here. Please choose a different value. | ||
18 | <Parameter Type="System.String" Name="elementName" /> | ||
19 | <Parameter Type="System.String" Name="attributeName" /> | ||
20 | <Parameter Type="System.String" Name="attributeValue" /> | ||
21 | </Instance> | ||
22 | </Message> | ||
23 | </Class> | ||
24 | <Class Name="DependencyWarnings" ContainerName="DependencyWarningEventArgs" BaseContainerName="MessageEventArgs"> | ||
25 | <Message Id="ProvidesKeyNotFound" Number="5431"> | ||
26 | <Instance> | ||
27 | The provider key with identifier {0} was not found in the WixDependencyProvider table. Related registry rows will not be removed from authoring. | ||
28 | <Parameter Type="System.String" Name="id" /> | ||
29 | </Instance> | ||
30 | </Message> | ||
31 | <Message Id="RequiresKeyNotFound" Number="5432"> | ||
32 | <Instance> | ||
33 | The dependency key with identifier {0} was not found in the WixDependency table. Related registry rows will not be removed from authoring. | ||
34 | <Parameter Type="System.String" Name="id" /> | ||
35 | </Instance> | ||
36 | </Message> | ||
37 | <Message Id="PropertyRemoved" Number="5433" SourceLineNumbers="no"> | ||
38 | <Instance> | ||
39 | The property {0} was authored in the package with a value and will be removed. The property should not be authored. | ||
40 | <Parameter Type="System.String" Name="name" /> | ||
41 | </Instance> | ||
42 | </Message> | ||
43 | <Message Id="DiscouragedVersionAttribute" Number="5434"> | ||
44 | <Instance> | ||
45 | The Provides/@Version attribute should not be specified in an MSI package. The ProductVersion will be used by default. | ||
46 | </Instance> | ||
47 | <Instance> | ||
48 | The Provides/@Version attribute should not be specified for MSI package {0}. The ProductVersion will be used by default. | ||
49 | <Parameter Type="System.String" Name="id" /> | ||
50 | </Instance> | ||
51 | </Message> | ||
52 | <Message Id="Win64Component" Number="5435"> | ||
53 | <Instance> | ||
54 | 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. | ||
55 | <Parameter Type="System.String" Name="componentId" /> | ||
56 | </Instance> | ||
57 | </Message> | ||
58 | </Class> | ||
59 | <Class Name="DependencyVerboses" ContainerName="DependencyVerboseEventArgs" BaseContainerName="MessageEventArgs" /> | ||
60 | </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 @@ | |||
1 | <?xml version="1.0" encoding="utf-8" ?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | |||
5 | <tableDefinitions xmlns="http://wixtoolset.org/schemas/v4/wi/tables"> | ||
6 | <tableDefinition name="WixDependencyProvider" createSymbols="yes"> | ||
7 | <columnDefinition name="WixDependencyProvider" type="string" length="72" primaryKey="yes" modularize="column" | ||
8 | category="identifier" description="The non-localized primary key for the table."/> | ||
9 | <columnDefinition name="Component_" type="string" length="72" keyTable="Component" keyColumn="1" modularize="column" | ||
10 | category="identifier" description="The foreign key into the Component table used to determine install state."/> | ||
11 | <columnDefinition name="ProviderKey" type="string" length="255" | ||
12 | category="text" description="The name of the registry key that holds the provider identity."/> | ||
13 | <columnDefinition name="Version" type="string" length="72" nullable="yes" | ||
14 | category="version" description="The version of the package."/> | ||
15 | <columnDefinition name="DisplayName" type="string" length="255" nullable="yes" | ||
16 | category="text" description="The display name of the package."/> | ||
17 | <columnDefinition name="Attributes" type="number" length="4" nullable="yes" | ||
18 | minValue="0" maxValue="2147483647" description="A 32-bit word that specifies the attribute flags to be applied."/> | ||
19 | </tableDefinition> | ||
20 | <tableDefinition name="WixDependency" createSymbols="yes"> | ||
21 | <columnDefinition name="WixDependency" type="string" length="72" primaryKey="yes" modularize="column" | ||
22 | category="identifier" description="The non-localized primary key for the table."/> | ||
23 | <columnDefinition name="ProviderKey" type="string" length="255" | ||
24 | category="text" description="The name of the registry key that holds the provider identity."/> | ||
25 | <columnDefinition name="MinVersion" type="string" length="72" nullable="yes" | ||
26 | category="version" description="The minimum version of the provider supported."/> | ||
27 | <columnDefinition name="MaxVersion" type="string" length="72" nullable="yes" | ||
28 | category="version" description="The maximum version of the provider supported."/> | ||
29 | <columnDefinition name="Attributes" type="number" length="4" nullable="yes" | ||
30 | minValue="0" maxValue="2147483647" description="A 32-bit word that specifies the attribute flags to be applied."/> | ||
31 | </tableDefinition> | ||
32 | <tableDefinition name="WixDependencyRef" createSymbols="yes"> | ||
33 | <columnDefinition name="WixDependencyProvider_" type="string" length="72" primaryKey="yes" keyTable="WixDependencyProvider" keyColumn="1" modularize="column" | ||
34 | category="identifier" description="Foreign key into the Component table." /> | ||
35 | <columnDefinition name="WixDependency_" type="string" length="72" primaryKey="yes" keyTable="WixDependency" keyColumn="1" modularize="column" | ||
36 | category="identifier" description="Foreign key into the WixDependency table." /> | ||
37 | </tableDefinition> | ||
38 | </tableDefinitions> | ||