aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-03-03 10:37:34 -0800
committerRob Mensching <rob@firegiant.com>2021-03-03 12:03:35 -0800
commit816bfd180f132a9b07aaa573f5ac0f5948195764 (patch)
treeeccb0db93007e00d3d8175f423338e960a7778f8 /src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
parente362f93f9fa9ed4b174333d44fcda25790bc85e0 (diff)
downloadwix-816bfd180f132a9b07aaa573f5ac0f5948195764.tar.gz
wix-816bfd180f132a9b07aaa573f5ac0f5948195764.tar.bz2
wix-816bfd180f132a9b07aaa573f5ac0f5948195764.zip
Complete MOVE_TO_BACKEND code migration
Fixes wixtoolset/issues#6212
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs296
1 files changed, 295 insertions, 1 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
index dc60a9ac..9ec26964 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
@@ -25,6 +25,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
25 this.TableDefinitions = tableDefinitions; 25 this.TableDefinitions = tableDefinitions;
26 this.BackendExtensions = backendExtensions; 26 this.BackendExtensions = backendExtensions;
27 this.BackendHelper = backendHelper; 27 this.BackendHelper = backendHelper;
28 this.GeneratedShortNames = new Dictionary<string, List<FileSymbol>>();
28 } 29 }
29 30
30 private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; } 31 private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; }
@@ -37,6 +38,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
37 38
38 private IntermediateSection Section { get; } 39 private IntermediateSection Section { get; }
39 40
41 private Dictionary<string, List<FileSymbol>> GeneratedShortNames { get; }
42
40 public WindowsInstallerData Data { get; private set; } 43 public WindowsInstallerData Data { get; private set; }
41 44
42 public WindowsInstallerData Execute() 45 public WindowsInstallerData Execute()
@@ -136,6 +139,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
136 139
137 case SymbolDefinitionType.ModuleConfiguration: 140 case SymbolDefinitionType.ModuleConfiguration:
138 this.AddModuleConfigurationSymbol((ModuleConfigurationSymbol)symbol); 141 this.AddModuleConfigurationSymbol((ModuleConfigurationSymbol)symbol);
142 this.EnsureModuleIgnoredTable(symbol, "ModuleConfiguration");
143 break;
144
145 case SymbolDefinitionType.ModuleSubstitution:
146 this.EnsureModuleIgnoredTable(symbol, "ModuleSubstitution");
139 break; 147 break;
140 148
141 case SymbolDefinitionType.MsiEmbeddedUI: 149 case SymbolDefinitionType.MsiEmbeddedUI:
@@ -262,6 +270,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
262 } 270 }
263 271
264 this.AddIndexedCellSymbols(cellsByTableAndRowId); 272 this.AddIndexedCellSymbols(cellsByTableAndRowId);
273 this.EnsureRequiredTables();
274 this.ReportGeneratedShortFileNameConflicts();
275 this.ReportIllegalTables();
276 this.ReportMismatchedModularizations();
277 this.ReportWindowsInstallerDataInconsistencies();
265 } 278 }
266 279
267 private void AddAssemblySymbol(AssemblySymbol symbol) 280 private void AddAssemblySymbol(AssemblySymbol symbol)
@@ -426,6 +439,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind
426 row[2] = symbol.Source; 439 row[2] = symbol.Source;
427 row[3] = symbol.Target; 440 row[3] = symbol.Target;
428 row[4] = symbol.PatchUninstall ? (int?)WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall : null; 441 row[4] = symbol.PatchUninstall ? (int?)WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall : null;
442
443 if (OutputType.Module == this.Data.Type)
444 {
445 this.Data.EnsureTable(this.TableDefinitions["AdminExecuteSequence"]);
446 this.Data.EnsureTable(this.TableDefinitions["AdminUISequence"]);
447 this.Data.EnsureTable(this.TableDefinitions["AdvtExecuteSequence"]);
448 this.Data.EnsureTable(this.TableDefinitions["InstallExecuteSequence"]);
449 this.Data.EnsureTable(this.TableDefinitions["InstallUISequence"]);
450 }
429 } 451 }
430 452
431 private void AddDialogSymbol(DialogSymbol symbol) 453 private void AddDialogSymbol(DialogSymbol symbol)
@@ -483,6 +505,38 @@ namespace WixToolset.Core.WindowsInstaller.Bind
483 row[0] = symbol.Id.Id; 505 row[0] = symbol.Id.Id;
484 row[1] = symbol.ParentDirectoryRef; 506 row[1] = symbol.ParentDirectoryRef;
485 row[2] = defaultDir; 507 row[2] = defaultDir;
508
509 if (OutputType.Module == this.Data.Type)
510 {
511 var directoryId = symbol.Id.Id;
512
513 if (WindowsInstallerStandard.IsStandardDirectory(directoryId))
514 {
515 // If the directory table contains references to standard windows folders
516 // mergemod.dll will add customactions to set the MSM directory to
517 // the same directory as the standard windows folder and will add references to
518 // custom action to all the standard sequence tables. A problem will occur
519 // if the MSI does not have these tables as mergemod.dll does not add these
520 // tables to the MSI if absent. This code adds the tables in case mergemod.dll
521 // needs them.
522 this.Data.EnsureTable(this.TableDefinitions["CustomAction"]);
523 this.Data.EnsureTable(this.TableDefinitions["AdminExecuteSequence"]);
524 this.Data.EnsureTable(this.TableDefinitions["AdminUISequence"]);
525 this.Data.EnsureTable(this.TableDefinitions["AdvtExecuteSequence"]);
526 this.Data.EnsureTable(this.TableDefinitions["InstallExecuteSequence"]);
527 this.Data.EnsureTable(this.TableDefinitions["InstallUISequence"]);
528 }
529 else
530 {
531 foreach (var standardDirectory in WindowsInstallerStandard.StandardDirectories())
532 {
533 if (directoryId.StartsWith(standardDirectory.Id.Id, StringComparison.Ordinal))
534 {
535 this.Messaging.Write(WarningMessages.StandardDirectoryConflictInMergeModule(symbol.SourceLineNumbers, directoryId, standardDirectory.Id.Id));
536 }
537 }
538 }
539 }
486 } 540 }
487 541
488 private void AddDuplicateFileSymbol(DuplicateFileSymbol symbol) 542 private void AddDuplicateFileSymbol(DuplicateFileSymbol symbol)
@@ -570,6 +624,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
570 if (null == symbol.ShortName && null != name && !Common.IsValidShortFilename(name, false)) 624 if (null == symbol.ShortName && null != name && !Common.IsValidShortFilename(name, false))
571 { 625 {
572 symbol.ShortName = CreateShortName(name, true, false, "File", symbol.DirectoryRef); 626 symbol.ShortName = CreateShortName(name, true, false, "File", symbol.DirectoryRef);
627
628 if (!this.GeneratedShortNames.TryGetValue(symbol.ShortName, out var potentialConflicts))
629 {
630 potentialConflicts = new List<FileSymbol>();
631 this.GeneratedShortNames.Add(symbol.ShortName, potentialConflicts);
632 }
633
634 potentialConflicts.Add(symbol);
573 } 635 }
574 636
575 var row = (FileRow)this.CreateRow(symbol, "File"); 637 var row = (FileRow)this.CreateRow(symbol, "File");
@@ -612,7 +674,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
612 var tableName = (IniFileActionType.AddLine == symbol.Action || IniFileActionType.AddTag == symbol.Action || IniFileActionType.CreateLine == symbol.Action) ? "IniFile" : "RemoveIniFile"; 674 var tableName = (IniFileActionType.AddLine == symbol.Action || IniFileActionType.AddTag == symbol.Action || IniFileActionType.CreateLine == symbol.Action) ? "IniFile" : "RemoveIniFile";
613 675
614 var name = symbol.FileName; 676 var name = symbol.FileName;
615 if (null == symbol.ShortFileName && null != name && !Common.IsValidShortFilename(name, false)) 677 if (null == symbol.ShortFileName && null != name && !Common.IsValidShortFilename(name, false))
616 { 678 {
617 symbol.ShortFileName = CreateShortName(name, true, false, "IniFile", symbol.ComponentRef); 679 symbol.ShortFileName = CreateShortName(name, true, false, "IniFile", symbol.ComponentRef);
618 } 680 }
@@ -1168,6 +1230,238 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1168 private bool AddSymbolDefaultly(IntermediateSymbol symbol) => 1230 private bool AddSymbolDefaultly(IntermediateSymbol symbol) =>
1169 this.BackendHelper.TryAddSymbolToMatchingTableDefinitions(this.Section, symbol, this.Data, this.TableDefinitions); 1231 this.BackendHelper.TryAddSymbolToMatchingTableDefinitions(this.Section, symbol, this.Data, this.TableDefinitions);
1170 1232
1233 private void EnsureModuleIgnoredTable(IntermediateSymbol symbol, string ignoredTable)
1234 {
1235 var tableDefinition = this.TableDefinitions["ModuleIgnoreTable"];
1236 var table = this.Data.EnsureTable(tableDefinition);
1237 if (!table.Rows.Any(r => r.FieldAsString(0) == ignoredTable))
1238 {
1239 var row = this.CreateRow(symbol, tableDefinition);
1240 row[0] = ignoredTable;
1241 }
1242 }
1243
1244 private void EnsureRequiredTables()
1245 {
1246 // check for missing table and add them or display an error as appropriate
1247 switch (this.Data.Type)
1248 {
1249 case OutputType.Module:
1250 this.Data.EnsureTable(this.TableDefinitions["Component"]);
1251 this.Data.EnsureTable(this.TableDefinitions["Directory"]);
1252 this.Data.EnsureTable(this.TableDefinitions["FeatureComponents"]);
1253 this.Data.EnsureTable(this.TableDefinitions["File"]);
1254 this.Data.EnsureTable(this.TableDefinitions["ModuleComponents"]);
1255 this.Data.EnsureTable(this.TableDefinitions["ModuleSignature"]);
1256 break;
1257
1258 case OutputType.PatchCreation:
1259 var imageFamiliesCount = this.Data.Tables["ImageFamilies"]?.Rows.Count ?? 0;
1260 var targetImagesCount = this.Data.Tables["TargetImages"]?.Rows.Count ?? 0;
1261 var upgradedImagesCount = this.Data.Tables["UpgradedImages"]?.Rows.Count ?? 0;
1262
1263 if (imageFamiliesCount < 1)
1264 {
1265 this.Messaging.Write(ErrorMessages.ExpectedRowInPatchCreationPackage("ImageFamilies"));
1266 }
1267
1268 if (targetImagesCount < 1)
1269 {
1270 this.Messaging.Write(ErrorMessages.ExpectedRowInPatchCreationPackage("TargetImages"));
1271 }
1272
1273 if (upgradedImagesCount < 1)
1274 {
1275 this.Messaging.Write(ErrorMessages.ExpectedRowInPatchCreationPackage("UpgradedImages"));
1276 }
1277
1278 this.Data.EnsureTable(this.TableDefinitions["Properties"]);
1279 break;
1280
1281 case OutputType.Product:
1282 this.Data.EnsureTable(this.TableDefinitions["File"]);
1283 this.Data.EnsureTable(this.TableDefinitions["Media"]);
1284 break;
1285 }
1286 }
1287
1288 private void ReportGeneratedShortFileNameConflicts()
1289 {
1290 foreach (var conflicts in this.GeneratedShortNames.Values.Where(l => l.Count > 1))
1291 {
1292 this.Messaging.Write(WarningMessages.GeneratedShortFileNameConflict(conflicts[0].SourceLineNumbers, conflicts[0].ShortName));
1293 for (var i = 1; i < conflicts.Count; ++i)
1294 {
1295 this.Messaging.Write(WarningMessages.GeneratedShortFileNameConflict2(conflicts[i].SourceLineNumbers));
1296 }
1297 }
1298 }
1299
1300 private void ReportIllegalTables()
1301 {
1302 foreach (var table in this.Data.Tables)
1303 {
1304 switch (this.Data.Type)
1305 {
1306 case OutputType.Module:
1307 if ("BBControl" == table.Name ||
1308 "Billboard" == table.Name ||
1309 "CCPSearch" == table.Name ||
1310 "Feature" == table.Name ||
1311 "LaunchCondition" == table.Name ||
1312 "Media" == table.Name ||
1313 "Patch" == table.Name ||
1314 "Upgrade" == table.Name ||
1315 "WixMerge" == table.Name)
1316 {
1317 foreach (Row row in table.Rows)
1318 {
1319 this.Messaging.Write(ErrorMessages.UnexpectedTableInMergeModule(row.SourceLineNumbers, table.Name));
1320 }
1321 }
1322 else if ("Error" == table.Name)
1323 {
1324 foreach (var row in table.Rows)
1325 {
1326 this.Messaging.Write(WarningMessages.DangerousTableInMergeModule(row.SourceLineNumbers, table.Name));
1327 }
1328 }
1329 break;
1330
1331 case OutputType.PatchCreation:
1332 if (!table.Definition.Unreal &&
1333 "_SummaryInformation" != table.Name &&
1334 "ExternalFiles" != table.Name &&
1335 "FamilyFileRanges" != table.Name &&
1336 "ImageFamilies" != table.Name &&
1337 "PatchMetadata" != table.Name &&
1338 "PatchSequence" != table.Name &&
1339 "Properties" != table.Name &&
1340 "TargetFiles_OptionalData" != table.Name &&
1341 "TargetImages" != table.Name &&
1342 "UpgradedFiles_OptionalData" != table.Name &&
1343 "UpgradedFilesToIgnore" != table.Name &&
1344 "UpgradedImages" != table.Name)
1345 {
1346 foreach (var row in table.Rows)
1347 {
1348 this.Messaging.Write(ErrorMessages.UnexpectedTableInPatchCreationPackage(row.SourceLineNumbers, table.Name));
1349 }
1350 }
1351 break;
1352
1353 case OutputType.Patch:
1354 if (!table.Definition.Unreal &&
1355 "_SummaryInformation" != table.Name &&
1356 "Media" != table.Name &&
1357 "MsiFileHash" != table.Name &&
1358 "MsiPatchMetadata" != table.Name &&
1359 "MsiPatchSequence" != table.Name)
1360 {
1361 foreach (var row in table.Rows)
1362 {
1363 this.Messaging.Write(ErrorMessages.UnexpectedTableInPatch(row.SourceLineNumbers, table.Name));
1364 }
1365 }
1366 break;
1367
1368 case OutputType.Product:
1369 if ("ModuleAdminExecuteSequence" == table.Name ||
1370 "ModuleAdminUISequence" == table.Name ||
1371 "ModuleAdvtExecuteSequence" == table.Name ||
1372 "ModuleAdvtUISequence" == table.Name ||
1373 "ModuleComponents" == table.Name ||
1374 "ModuleConfiguration" == table.Name ||
1375 "ModuleDependency" == table.Name ||
1376 "ModuleExclusion" == table.Name ||
1377 "ModuleIgnoreTable" == table.Name ||
1378 "ModuleInstallExecuteSequence" == table.Name ||
1379 "ModuleInstallUISequence" == table.Name ||
1380 "ModuleSignature" == table.Name ||
1381 "ModuleSubstitution" == table.Name)
1382 {
1383 foreach (var row in table.Rows)
1384 {
1385 this.Messaging.Write(WarningMessages.UnexpectedTableInProduct(row.SourceLineNumbers, table.Name));
1386 }
1387 }
1388 break;
1389 }
1390 }
1391 }
1392
1393 private void ReportMismatchedModularizations()
1394 {
1395 // verify that modularization types match for foreign key relationships
1396 foreach (var tableDefinition in this.TableDefinitions)
1397 {
1398 foreach (var columnDefinition in tableDefinition.Columns)
1399 {
1400 if (null != columnDefinition.KeyTable && 0 > columnDefinition.KeyTable.IndexOf(';') && columnDefinition.KeyColumn.HasValue)
1401 {
1402 if (this.TableDefinitions.TryGet(columnDefinition.KeyTable, out var keyTableDefinition))
1403 {
1404 var keyColumnIndex = columnDefinition.KeyColumn ?? -1;
1405
1406 if (keyColumnIndex <= 0 || keyColumnIndex > keyTableDefinition.Columns.Length)
1407 {
1408 this.Messaging.Write(ErrorMessages.InvalidKeyColumn(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, keyColumnIndex));
1409 }
1410 else if (keyTableDefinition.Columns[keyColumnIndex - 1].ModularizeType != columnDefinition.ModularizeType && ColumnModularizeType.CompanionFile != columnDefinition.ModularizeType)
1411 {
1412 this.Messaging.Write(ErrorMessages.CollidingModularizationTypes(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, keyColumnIndex, columnDefinition.ModularizeType.ToString(), keyTableDefinition.Columns[keyColumnIndex - 1].ModularizeType.ToString()));
1413 }
1414 }
1415 // else - ignore missing table definitions as that error is caught in other places
1416 }
1417 }
1418 }
1419 }
1420
1421 private void ReportWindowsInstallerDataInconsistencies()
1422 {
1423 // Get the output's minimum installer version
1424 var outputInstallerVersion = Int32.MaxValue;
1425
1426 if (this.Data.Tables.TryGetTable("_SummaryInformation", out var summaryInformationTable))
1427 {
1428 outputInstallerVersion = summaryInformationTable.Rows.FirstOrDefault(r => 14 == r.FieldAsInteger(0))?.FieldAsInteger(1) ?? Int32.MaxValue;
1429 }
1430
1431 // Ensure the Error table exists if output is marked for MSI 1.0 or below (see ICE40).
1432 if (outputInstallerVersion <= 100 && OutputType.Product == this.Data.Type)
1433 {
1434 this.Data.EnsureTable(this.TableDefinitions["Error"]);
1435 }
1436
1437 // Check for the presence of tables/rows/columns that require MSI 1.1 or later.
1438 if (outputInstallerVersion < 110)
1439 {
1440 if (this.Data.Tables.TryGetTable("IsolatedComponent", out var isolatedComponentTable))
1441 {
1442 foreach (var row in isolatedComponentTable.Rows)
1443 {
1444 this.Messaging.Write(WarningMessages.TableIncompatibleWithInstallerVersion(row.SourceLineNumbers, "IsolatedComponent", outputInstallerVersion));
1445 }
1446 }
1447 }
1448
1449 // Check for the presence of tables/rows/columns that require MSI 4.0 or later
1450 if (outputInstallerVersion < 400)
1451 {
1452 if (this.Data.Tables.TryGetTable("Shortcut", out var shortcutTable))
1453 {
1454 foreach (var row in shortcutTable.Rows)
1455 {
1456 if (null != row[12] || null != row[13] || null != row[14] || null != row[15])
1457 {
1458 this.Messaging.Write(WarningMessages.ColumnsIncompatibleWithInstallerVersion(row.SourceLineNumbers, "Shortcut", outputInstallerVersion));
1459 }
1460 }
1461 }
1462 }
1463 }
1464
1171 private static OutputType SectionTypeToOutputType(SectionType type) 1465 private static OutputType SectionTypeToOutputType(SectionType type)
1172 { 1466 {
1173 switch (type) 1467 switch (type)