main
cs 251 lines 13.6 KB
Raw
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.Core.WindowsInstaller.Bind
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Core.Native.Msi;
9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11 using WixToolset.Data.WindowsInstaller;
12 using WixToolset.Data.WindowsInstaller.Rows;
13 using WixToolset.Extensibility.Services;
14
15 internal class CreateInstanceTransformsCommand
16 {
17 public CreateInstanceTransformsCommand(IntermediateSection section, WindowsInstallerData output, TableDefinitionCollection tableDefinitions, IBackendHelper backendHelper)
18 {
19 this.Section = section;
20 this.Output = output;
21 this.TableDefinitions = tableDefinitions;
22 this.BackendHelper = backendHelper;
23 }
24
25 private IntermediateSection Section { get; }
26
27 private WindowsInstallerData Output { get; }
28
29 public TableDefinitionCollection TableDefinitions { get; }
30
31 private IBackendHelper BackendHelper { get; }
32
33 public IReadOnlyCollection<SubStorage> SubStorages { get; private set; }
34
35 public IReadOnlyCollection<SubStorage> Execute()
36 {
37 var subStorages = new List<SubStorage>();
38
39 // Create and add substorages for instance transforms.
40 var wixInstanceTransformsSymbols = this.Section.Symbols.OfType<WixInstanceTransformsSymbol>();
41
42 if (wixInstanceTransformsSymbols.Any())
43 {
44 var targetSummaryInformationTable = this.Output.Tables["_SummaryInformation"];
45 var targetPropertyRows = new RowDictionary<PropertyRow>(this.Output.Tables["Property"]);
46 PropertyRow propertyRow = null;
47
48 // Get the data from target database
49 var targetProductCode = targetPropertyRows.TryGetValue("ProductCode", out propertyRow) ? propertyRow.Value : null;
50 var targetProductVersion = targetPropertyRows.TryGetValue("ProductVersion", out propertyRow) ? propertyRow.Value : null;
51 var targetUpgradeCode = targetPropertyRows.TryGetValue("UpgradeCode", out propertyRow) ? propertyRow.Value : null;
52
53 // Index the Instance Component Rows, we'll get the Components rows from the real Component table.
54 var instanceComponentSymbols = this.Section.Symbols.OfType<WixInstanceComponentSymbol>().ToDictionary(t => t.Id.Id, t => (ComponentRow)null);
55
56 if (instanceComponentSymbols.Any())
57 {
58 var targetComponentTable = this.Output.Tables["Component"];
59 foreach (ComponentRow componentRow in targetComponentTable.Rows)
60 {
61 var component = (string)componentRow[0];
62 if (instanceComponentSymbols.ContainsKey(component))
63 {
64 instanceComponentSymbols[component] = componentRow;
65 }
66 }
67 }
68
69 // Generate the instance transforms
70 foreach (var instanceSymbol in wixInstanceTransformsSymbols)
71 {
72 var instanceId = instanceSymbol.Id.Id;
73
74 var instanceTransform = new WindowsInstallerData(instanceSymbol.SourceLineNumbers);
75 instanceTransform.Type = OutputType.Transform;
76 instanceTransform.Codepage = this.Output.Codepage;
77
78 var instanceSummaryInformationTable = instanceTransform.EnsureTable(this.TableDefinitions["_SummaryInformation"]);
79 string targetPlatformAndLanguage = null;
80
81 foreach (var summaryInformationRow in targetSummaryInformationTable.Rows)
82 {
83 if (7 == (int)summaryInformationRow[0]) // PID_TEMPLATE
84 {
85 targetPlatformAndLanguage = (string)summaryInformationRow[1];
86 }
87
88 // Copy the row's data to the transform.
89 var copyOfSummaryRow = instanceSummaryInformationTable.CreateRow(summaryInformationRow.SourceLineNumbers);
90 copyOfSummaryRow[0] = summaryInformationRow[0];
91 copyOfSummaryRow[1] = summaryInformationRow[1];
92 }
93
94 // Modify the appropriate properties.
95 var propertyTable = instanceTransform.EnsureTable(this.TableDefinitions["Property"]);
96
97 // Change the ProductCode property
98 var productCode = instanceSymbol.ProductCode;
99 if ("*" == productCode)
100 {
101 productCode = this.BackendHelper.CreateGuid();
102 }
103
104 var productCodeRow = propertyTable.CreateRow(instanceSymbol.SourceLineNumbers);
105 productCodeRow.Operation = RowOperation.Modify;
106 productCodeRow.Fields[1].Modified = true;
107 productCodeRow[0] = "ProductCode";
108 productCodeRow[1] = productCode;
109
110 // Set the instance property. If the property exists in the MSI already, mark the row as modified in the transform.
111 // Otherwise, we need to mark the row as an add.
112 var instanceIdRow = propertyTable.CreateRow(instanceSymbol.SourceLineNumbers);
113 instanceIdRow.Operation = targetPropertyRows.ContainsKey(instanceSymbol.PropertyId) ? RowOperation.Modify : RowOperation.Add;
114 instanceIdRow.Fields[1].Modified = true;
115 instanceIdRow[0] = instanceSymbol.PropertyId;
116 instanceIdRow[1] = instanceId;
117
118 if (!String.IsNullOrEmpty(instanceSymbol.ProductName))
119 {
120 // Change the ProductName property
121 var productNameRow = propertyTable.CreateRow(instanceSymbol.SourceLineNumbers);
122 productNameRow.Operation = RowOperation.Modify;
123 productNameRow.Fields[1].Modified = true;
124 productNameRow[0] = "ProductName";
125 productNameRow[1] = instanceSymbol.ProductName;
126 }
127
128 if (!String.IsNullOrEmpty(instanceSymbol.UpgradeCode))
129 {
130 // Change the UpgradeCode property
131 var upgradeCodeRow = propertyTable.CreateRow(instanceSymbol.SourceLineNumbers);
132 upgradeCodeRow.Operation = RowOperation.Modify;
133 upgradeCodeRow.Fields[1].Modified = true;
134 upgradeCodeRow[0] = "UpgradeCode";
135 upgradeCodeRow[1] = instanceSymbol.UpgradeCode;
136
137 // Change the Upgrade table
138 var targetUpgradeTable = this.Output.Tables["Upgrade"];
139 if (null != targetUpgradeTable && 0 <= targetUpgradeTable.Rows.Count)
140 {
141 var upgradeId = instanceSymbol.UpgradeCode;
142 var upgradeTable = instanceTransform.EnsureTable(this.TableDefinitions["Upgrade"]);
143 foreach (var row in targetUpgradeTable.Rows)
144 {
145 // In case they are upgrading other codes to this new product, leave the ones that don't match the
146 // Product.UpgradeCode intact.
147 if (targetUpgradeCode == (string)row[0])
148 {
149 var upgradeRow = upgradeTable.CreateRow(row.SourceLineNumbers);
150 upgradeRow.Operation = RowOperation.Add;
151 upgradeRow.Fields[0].Modified = true;
152 // I was hoping to be able to RowOperation.Modify, but that didn't appear to function.
153 // upgradeRow.Fields[0].PreviousData = (string)row[0];
154
155 // Inserting a new Upgrade record with the updated UpgradeCode
156 upgradeRow[0] = upgradeId;
157 upgradeRow[1] = row[1];
158 upgradeRow[2] = row[2];
159 upgradeRow[3] = row[3];
160 upgradeRow[4] = row[4];
161 upgradeRow[5] = row[5];
162 upgradeRow[6] = row[6];
163
164 // Delete the old row
165 var upgradeRemoveRow = upgradeTable.CreateRow(row.SourceLineNumbers);
166 upgradeRemoveRow.Operation = RowOperation.Delete;
167 upgradeRemoveRow[0] = row[0];
168 upgradeRemoveRow[1] = row[1];
169 upgradeRemoveRow[2] = row[2];
170 upgradeRemoveRow[3] = row[3];
171 upgradeRemoveRow[4] = row[4];
172 upgradeRemoveRow[5] = row[5];
173 upgradeRemoveRow[6] = row[6];
174 }
175 }
176 }
177 }
178
179 // If there are instance Components generate new GUIDs for them.
180 if (0 < instanceComponentSymbols.Count)
181 {
182 var componentTable = instanceTransform.EnsureTable(this.TableDefinitions["Component"]);
183 foreach (var targetComponentRow in instanceComponentSymbols.Values)
184 {
185 var guid = targetComponentRow.Guid;
186 if (!String.IsNullOrEmpty(guid))
187 {
188 var instanceComponentRow = componentTable.CreateRow(targetComponentRow.SourceLineNumbers);
189 instanceComponentRow.Operation = RowOperation.Modify;
190 instanceComponentRow.Fields[1].Modified = true;
191 instanceComponentRow[0] = targetComponentRow[0];
192 instanceComponentRow[1] = this.BackendHelper.CreateGuid(BindDatabaseCommand.WixComponentGuidNamespace, String.Concat(guid, instanceId));
193 instanceComponentRow[2] = targetComponentRow[2];
194 instanceComponentRow[3] = targetComponentRow[3];
195 instanceComponentRow[4] = targetComponentRow[4];
196 instanceComponentRow[5] = targetComponentRow[5];
197 }
198 }
199 }
200
201 // Update the summary information
202 var summaryRows = new Dictionary<int, Row>(instanceSummaryInformationTable.Rows.Count);
203 foreach (var row in instanceSummaryInformationTable.Rows)
204 {
205 summaryRows[(int)row[0]] = row;
206
207 if ((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage == (int)row[0])
208 {
209 row[1] = targetPlatformAndLanguage;
210 }
211 else if ((int)SummaryInformation.Transform.ProductCodes == (int)row[0])
212 {
213 row[1] = String.Concat(targetProductCode, targetProductVersion, ';', productCode, targetProductVersion, ';', targetUpgradeCode);
214 }
215 else if ((int)SummaryInformation.Transform.ValidationFlags == (int)row[0])
216 {
217 row[1] = 0;
218 }
219 else if ((int)SummaryInformation.Transform.Security == (int)row[0])
220 {
221 row[1] = "4";
222 }
223 }
224
225 if (!summaryRows.ContainsKey((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage))
226 {
227 var summaryRow = instanceSummaryInformationTable.CreateRow(instanceSymbol.SourceLineNumbers);
228 summaryRow[0] = (int)SummaryInformation.Transform.UpdatedPlatformAndLanguage;
229 summaryRow[1] = targetPlatformAndLanguage;
230 }
231 else if (!summaryRows.ContainsKey((int)SummaryInformation.Transform.ValidationFlags))
232 {
233 var summaryRow = instanceSummaryInformationTable.CreateRow(instanceSymbol.SourceLineNumbers);
234 summaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
235 summaryRow[1] = "0";
236 }
237 else if (!summaryRows.ContainsKey((int)SummaryInformation.Transform.Security))
238 {
239 var summaryRow = instanceSummaryInformationTable.CreateRow(instanceSymbol.SourceLineNumbers);
240 summaryRow[0] = (int)SummaryInformation.Transform.Security;
241 summaryRow[1] = "4";
242 }
243
244 subStorages.Add(new SubStorage(instanceId, instanceTransform));
245 }
246 }
247
248 return this.SubStorages = subStorages;
249 }
250 }
251 }