diff options
Diffstat (limited to 'src/wixext/DependencyBinder.cs')
-rw-r--r-- | src/wixext/DependencyBinder.cs | 169 |
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 | |||
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 | } | ||