aboutsummaryrefslogtreecommitdiff
path: root/src/wixext/DependencyBinder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/wixext/DependencyBinder.cs')
-rw-r--r--src/wixext/DependencyBinder.cs169
1 files changed, 169 insertions, 0 deletions
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
3namespace 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}