aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs95
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs31
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs9
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs36
-rw-r--r--src/WixToolset.Core/Compiler.cs3
-rw-r--r--src/WixToolset.Core/ExtensibilityServices/PathResolver.cs51
-rw-r--r--src/WixToolset.Core/Link/ResolveReferencesCommand.cs25
-rw-r--r--src/WixToolset.Core/Link/SymbolWithSection.cs91
-rw-r--r--src/WixToolset.Core/Linker.cs22
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs89
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs7
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/CustomAction/SimpleCustomAction.wxs15
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs12
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/Directory/Empty.wxs6
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs6
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj2
17 files changed, 437 insertions, 72 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs
new file mode 100644
index 00000000..4597639b
--- /dev/null
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs
@@ -0,0 +1,95 @@
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.Core.WindowsInstaller.Bind
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
10 using WixToolset.Data.WindowsInstaller;
11
12 /// <summary>
13 /// Add referenced standard directory symbols, if not already present.
14 /// </summary>
15 internal class AddRequiredStandardDirectories
16 {
17 internal AddRequiredStandardDirectories(IntermediateSection section, Platform platform)
18 {
19 this.Section = section;
20 this.Platform = platform;
21 }
22
23 private IntermediateSection Section { get; }
24
25 private Platform Platform { get; }
26
27 public void Execute()
28 {
29 var directories = this.Section.Symbols.OfType<DirectorySymbol>().ToList();
30 var directoriesById = directories.ToDictionary(d => d.Id.Id);
31
32 foreach (var directory in directories)
33 {
34 var parentDirectoryId = directory.ParentDirectoryRef;
35
36 if (String.IsNullOrEmpty(parentDirectoryId))
37 {
38 if (directory.Id.Id != "TARGETDIR")
39 {
40 directory.ParentDirectoryRef = "TARGETDIR";
41 }
42 }
43 else
44 {
45 this.EnsureStandardDirectoryAdded(directoriesById, parentDirectoryId, directory.SourceLineNumbers);
46 }
47 }
48
49 if (!directoriesById.ContainsKey("TARGETDIR") && WindowsInstallerStandard.TryGetStandardDirectory("TARGETDIR", out var targetDir))
50 {
51 directoriesById.Add(targetDir.Id.Id, targetDir);
52 this.Section.AddSymbol(targetDir);
53 }
54 }
55
56 private void EnsureStandardDirectoryAdded(Dictionary<string, DirectorySymbol> directoriesById, string directoryId, SourceLineNumber sourceLineNumbers)
57 {
58 if (!directoriesById.ContainsKey(directoryId) && WindowsInstallerStandard.TryGetStandardDirectory(directoryId, out var standardDirectory))
59 {
60 var parentDirectoryId = this.GetStandardDirectoryParent(directoryId);
61
62 var directory = new DirectorySymbol(sourceLineNumbers, standardDirectory.Id)
63 {
64 Name = standardDirectory.Name,
65 ParentDirectoryRef = parentDirectoryId,
66 };
67
68 directoriesById.Add(directory.Id.Id, directory);
69 this.Section.AddSymbol(directory);
70
71 if (!String.IsNullOrEmpty(parentDirectoryId))
72 {
73 this.EnsureStandardDirectoryAdded(directoriesById, parentDirectoryId, sourceLineNumbers);
74 }
75 }
76 }
77
78 private string GetStandardDirectoryParent(string directoryId)
79 {
80 switch (directoryId)
81 {
82 case "TARGETDIR":
83 return null;
84
85 case "CommonFiles6432Folder":
86 case "ProgramFiles6432Folder":
87 case "System6432Folder":
88 return WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directoryId, this.Platform);
89
90 default:
91 return "TARGETDIR";
92 }
93 }
94 }
95}
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
index 950fe1c1..93c617d9 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
@@ -133,6 +133,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
133 bool compressed; 133 bool compressed;
134 bool longNames; 134 bool longNames;
135 int installerVersion; 135 int installerVersion;
136 Platform platform;
136 string modularizationSuffix; 137 string modularizationSuffix;
137 { 138 {
138 var command = new BindSummaryInfoCommand(section); 139 var command = new BindSummaryInfoCommand(section);
@@ -141,6 +142,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
141 compressed = command.Compressed; 142 compressed = command.Compressed;
142 longNames = command.LongNames; 143 longNames = command.LongNames;
143 installerVersion = command.InstallerVersion; 144 installerVersion = command.InstallerVersion;
145 platform = command.Platform;
144 modularizationSuffix = command.ModularizationSuffix; 146 modularizationSuffix = command.ModularizationSuffix;
145 } 147 }
146 148
@@ -194,6 +196,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
194 } 196 }
195 197
196 { 198 {
199 var command = new AddRequiredStandardDirectories(section, platform);
200 command.Execute();
201 }
202
203 {
197 var command = new CreateSpecialPropertiesCommand(section); 204 var command = new CreateSpecialPropertiesCommand(section);
198 command.Execute(); 205 command.Execute();
199 } 206 }
@@ -332,7 +339,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
332 339
333 // Set generated component guids. 340 // Set generated component guids.
334 { 341 {
335 var command = new CalculateComponentGuids(this.Messaging, this.BackendHelper, this.PathResolver, section); 342 var command = new CalculateComponentGuids(this.Messaging, this.BackendHelper, this.PathResolver, section, platform);
336 command.Execute(); 343 command.Execute();
337 } 344 }
338 345
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
index 82688edf..63691016 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
@@ -32,6 +32,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
32 32
33 public int InstallerVersion { get; private set; } 33 public int InstallerVersion { get; private set; }
34 34
35 public Platform Platform { get; private set; }
36
35 /// <summary> 37 /// <summary>
36 /// Modularization guid, or null if the output is not a module. 38 /// Modularization guid, or null if the output is not a module.
37 /// </summary> 39 /// </summary>
@@ -66,6 +68,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
66 summaryInformationSymbol.Value = Common.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture); 68 summaryInformationSymbol.Value = Common.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture);
67 } 69 }
68 break; 70 break;
71 case SummaryInformationType.PlatformAndLanguage:
72 this.Platform = GetPlatformFromSummaryInformation(summaryInformationSymbol.Value);
73 break;
74
69 case SummaryInformationType.PackageCode: // PID_REVNUMBER 75 case SummaryInformationType.PackageCode: // PID_REVNUMBER
70 var packageCode = summaryInformationSymbol.Value; 76 var packageCode = summaryInformationSymbol.Value;
71 77
@@ -137,5 +143,30 @@ namespace WixToolset.Core.WindowsInstaller.Bind
137 }); 143 });
138 } 144 }
139 } 145 }
146
147 private static Platform GetPlatformFromSummaryInformation(string value)
148 {
149 var separatorIndex = value.IndexOf(';');
150 var platformValue = separatorIndex > 0 ? value.Substring(0, separatorIndex) : value;
151
152 switch (platformValue)
153 {
154 case "x64":
155 return Platform.X64;
156
157 case "Arm":
158 return Platform.ARM;
159
160 case "Arm64":
161 return Platform.ARM64;
162
163 case "Intel64":
164 return Platform.IA64;
165
166 case "Intel":
167 default:
168 return Platform.X86;
169 }
170 }
140 } 171 }
141} 172}
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
index a1e3ac83..02336cae 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
@@ -16,12 +16,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
16 /// </summary> 16 /// </summary>
17 internal class CalculateComponentGuids 17 internal class CalculateComponentGuids
18 { 18 {
19 internal CalculateComponentGuids(IMessaging messaging, IBackendHelper helper, IPathResolver pathResolver, IntermediateSection section) 19 internal CalculateComponentGuids(IMessaging messaging, IBackendHelper helper, IPathResolver pathResolver, IntermediateSection section, Platform platform)
20 { 20 {
21 this.Messaging = messaging; 21 this.Messaging = messaging;
22 this.BackendHelper = helper; 22 this.BackendHelper = helper;
23 this.PathResolver = pathResolver; 23 this.PathResolver = pathResolver;
24 this.Section = section; 24 this.Section = section;
25 this.Platform = platform;
25 } 26 }
26 27
27 private IMessaging Messaging { get; } 28 private IMessaging Messaging { get; }
@@ -32,6 +33,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
32 33
33 private IntermediateSection Section { get; } 34 private IntermediateSection Section { get; }
34 35
36 private Platform Platform { get; }
37
35 public void Execute() 38 public void Execute()
36 { 39 {
37 Dictionary<string, RegistrySymbol> registryKeyRows = null; 40 Dictionary<string, RegistrySymbol> registryKeyRows = null;
@@ -42,7 +45,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
42 // Find components with generatable guids. 45 // Find components with generatable guids.
43 foreach (var componentSymbol in this.Section.Symbols.OfType<ComponentSymbol>()) 46 foreach (var componentSymbol in this.Section.Symbols.OfType<ComponentSymbol>())
44 { 47 {
45 // Skip components that do not specify generate guid. 48 // Skip components that do not specify generate guid.
46 if (componentSymbol.ComponentId != "*") 49 if (componentSymbol.ComponentId != "*")
47 { 50 {
48 continue; 51 continue;
@@ -135,7 +138,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
135 if (fileRow.Id.Id == componentSymbol.KeyPath) 138 if (fileRow.Id.Id == componentSymbol.KeyPath)
136 { 139 {
137 // calculate the key file's canonical target path 140 // calculate the key file's canonical target path
138 string directoryPath = this.PathResolver.GetDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentSymbol.DirectoryRef, true); 141 string directoryPath = this.PathResolver.GetCanonicalDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentSymbol.DirectoryRef, this.Platform);
139 string fileName = Common.GetName(fileRow.Name, false, true).ToLowerInvariant(); 142 string fileName = Common.GetName(fileRow.Name, false, true).ToLowerInvariant();
140 path = Path.Combine(directoryPath, fileName); 143 path = Path.Combine(directoryPath, fileName);
141 144
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs
index 7f43da9a..93e25878 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs
@@ -34,25 +34,25 @@ namespace WixToolset.Core.WindowsInstaller.Bind
34 { 34 {
35 var requiredActionSymbols = new Dictionary<string, WixActionSymbol>(); 35 var requiredActionSymbols = new Dictionary<string, WixActionSymbol>();
36 36
37 // Get the standard actions required based on symbols in the section.
38 var overridableActionSymbols = this.GetRequiredStandardActions();
39
40 // Index all the action symbols and look for collisions. 37 // Index all the action symbols and look for collisions.
41 foreach (var actionSymbol in this.Section.Symbols.OfType<WixActionSymbol>()) 38 foreach (var actionSymbol in this.Section.Symbols.OfType<WixActionSymbol>())
42 { 39 {
43 if (actionSymbol.Overridable) // overridable action 40 if (actionSymbol.Overridable) // overridable action
44 { 41 {
45 if (overridableActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol)) 42 if (requiredActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol))
46 { 43 {
47 this.Messaging.Write(ErrorMessages.OverridableActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); 44 if (collidingActionSymbol.Overridable)
48 if (null != collidingActionSymbol.SourceLineNumbers)
49 { 45 {
50 this.Messaging.Write(ErrorMessages.OverridableActionCollision2(collidingActionSymbol.SourceLineNumbers)); 46 this.Messaging.Write(ErrorMessages.OverridableActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action));
47 if (null != collidingActionSymbol.SourceLineNumbers)
48 {
49 this.Messaging.Write(ErrorMessages.OverridableActionCollision2(collidingActionSymbol.SourceLineNumbers));
50 }
51 } 51 }
52 } 52 }
53 else 53 else
54 { 54 {
55 overridableActionSymbols.Add(actionSymbol.Id.Id, actionSymbol); 55 requiredActionSymbols.Add(actionSymbol.Id.Id, actionSymbol);
56 } 56 }
57 } 57 }
58 else // unsequenced or sequenced action. 58 else // unsequenced or sequenced action.
@@ -71,7 +71,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
71 } 71 }
72 } 72 }
73 73
74 if (requiredActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol)) 74 if (requiredActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol) && !collidingActionSymbol.Overridable)
75 { 75 {
76 this.Messaging.Write(ErrorMessages.ActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); 76 this.Messaging.Write(ErrorMessages.ActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action));
77 if (null != collidingActionSymbol.SourceLineNumbers) 77 if (null != collidingActionSymbol.SourceLineNumbers)
@@ -81,13 +81,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
81 } 81 }
82 else 82 else
83 { 83 {
84 requiredActionSymbols.Add(actionSymbol.Id.Id, actionSymbol); 84 requiredActionSymbols[actionSymbol.Id.Id] = actionSymbol;
85 } 85 }
86 } 86 }
87 } 87 }
88 88
89 // Get the standard actions required based on symbols in the section.
90 var requiredStandardActions = this.GetRequiredStandardActions();
91
89 // Add the overridable action symbols that are not overridden to the required action symbols. 92 // Add the overridable action symbols that are not overridden to the required action symbols.
90 foreach (var actionSymbol in overridableActionSymbols.Values) 93 foreach (var actionSymbol in requiredStandardActions.Values)
91 { 94 {
92 if (!requiredActionSymbols.ContainsKey(actionSymbol.Id.Id)) 95 if (!requiredActionSymbols.ContainsKey(actionSymbol.Id.Id))
93 { 96 {
@@ -557,17 +560,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
557 return set; 560 return set;
558 } 561 }
559 562
560 private IEnumerable<WixActionSymbol> GetActions(SequenceTable sequence, string[] actionNames)
561 {
562 foreach (var action in WindowsInstallerStandard.StandardActions())
563 {
564 if (action.SequenceTable == sequence && actionNames.Contains(action.Action))
565 {
566 yield return action;
567 }
568 }
569 }
570
571 /// <summary> 563 /// <summary>
572 /// Sequence an action before or after a standard action. 564 /// Sequence an action before or after a standard action.
573 /// </summary> 565 /// </summary>
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs
index c504e96f..c641bceb 100644
--- a/src/WixToolset.Core/Compiler.cs
+++ b/src/WixToolset.Core/Compiler.cs
@@ -4279,8 +4279,7 @@ namespace WixToolset.Core
4279 this.Core.AddInlineDirectoryId(inlineSyntax, id.Id); 4279 this.Core.AddInlineDirectoryId(inlineSyntax, id.Id);
4280 } 4280 }
4281 } 4281 }
4282 4282 else if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !("SourceDir".Equals(name, StringComparison.Ordinal) && shortName == null && shortSourceName == null && sourceName == null))
4283 if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !("SourceDir".Equals(name, StringComparison.Ordinal) && shortName == null && shortSourceName == null && sourceName == null))
4284 { 4283 {
4285 this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, name)); 4284 this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, name));
4286 } 4285 }
diff --git a/src/WixToolset.Core/ExtensibilityServices/PathResolver.cs b/src/WixToolset.Core/ExtensibilityServices/PathResolver.cs
index 15cd4fc9..72be2bcb 100644
--- a/src/WixToolset.Core/ExtensibilityServices/PathResolver.cs
+++ b/src/WixToolset.Core/ExtensibilityServices/PathResolver.cs
@@ -12,7 +12,7 @@ namespace WixToolset.Core.ExtensibilityServices
12 12
13 internal class PathResolver : IPathResolver 13 internal class PathResolver : IPathResolver
14 { 14 {
15 public string GetDirectoryPath(Dictionary<string, IResolvedDirectory> directories, Dictionary<string, string> componentIdGenSeeds, string directory, bool canonicalize) 15 public string GetCanonicalDirectoryPath(Dictionary<string, IResolvedDirectory> directories, Dictionary<string, string> componentIdGenSeeds, string directory, Platform platform)
16 { 16 {
17 if (!directories.TryGetValue(directory, out var resolvedDirectory)) 17 if (!directories.TryGetValue(directory, out var resolvedDirectory))
18 { 18 {
@@ -25,19 +25,13 @@ namespace WixToolset.Core.ExtensibilityServices
25 { 25 {
26 resolvedDirectory.Path = componentIdGenSeeds[directory]; 26 resolvedDirectory.Path = componentIdGenSeeds[directory];
27 } 27 }
28 else if (canonicalize && WindowsInstallerStandard.IsStandardDirectory(directory)) 28 else if (WindowsInstallerStandard.IsStandardDirectory(directory))
29 { 29 {
30 // when canonicalization is on, standard directories are treated equally 30 resolvedDirectory.Path = WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directory, platform);
31 resolvedDirectory.Path = directory;
32 } 31 }
33 else 32 else
34 { 33 {
35 string name = resolvedDirectory.Name; 34 var name = resolvedDirectory.Name?.ToLowerInvariant();
36
37 if (canonicalize)
38 {
39 name = name?.ToLowerInvariant();
40 }
41 35
42 if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent)) 36 if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent))
43 { 37 {
@@ -45,7 +39,7 @@ namespace WixToolset.Core.ExtensibilityServices
45 } 39 }
46 else 40 else
47 { 41 {
48 var parentPath = this.GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize); 42 var parentPath = this.GetCanonicalDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, platform);
49 43
50 if (null != resolvedDirectory.Name) 44 if (null != resolvedDirectory.Name)
51 { 45 {
@@ -62,6 +56,39 @@ namespace WixToolset.Core.ExtensibilityServices
62 return resolvedDirectory.Path; 56 return resolvedDirectory.Path;
63 } 57 }
64 58
59 public string GetDirectoryPath(Dictionary<string, IResolvedDirectory> directories, string directory)
60 {
61 if (!directories.TryGetValue(directory, out var resolvedDirectory))
62 {
63 throw new WixException(ErrorMessages.ExpectedDirectory(directory));
64 }
65
66 if (null == resolvedDirectory.Path)
67 {
68 var name = resolvedDirectory.Name;
69
70 if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent))
71 {
72 resolvedDirectory.Path = name;
73 }
74 else
75 {
76 var parentPath = this.GetDirectoryPath(directories, resolvedDirectory.DirectoryParent);
77
78 if (null != resolvedDirectory.Name)
79 {
80 resolvedDirectory.Path = Path.Combine(parentPath, name);
81 }
82 else
83 {
84 resolvedDirectory.Path = parentPath;
85 }
86 }
87 }
88
89 return resolvedDirectory.Path;
90 }
91
65 public string GetFileSourcePath(Dictionary<string, IResolvedDirectory> directories, string directoryId, string fileName, bool compressed, bool useLongName) 92 public string GetFileSourcePath(Dictionary<string, IResolvedDirectory> directories, string directoryId, string fileName, bool compressed, bool useLongName)
66 { 93 {
67 var fileSourcePath = Common.GetName(fileName, true, useLongName); 94 var fileSourcePath = Common.GetName(fileName, true, useLongName);
@@ -75,7 +102,7 @@ namespace WixToolset.Core.ExtensibilityServices
75 { 102 {
76 // Get the relative path of where we want the file to be layed out as specified 103 // Get the relative path of where we want the file to be layed out as specified
77 // in the Directory table. 104 // in the Directory table.
78 var directoryPath = this.GetDirectoryPath(directories, null, directoryId, false); 105 var directoryPath = this.GetDirectoryPath(directories, directoryId);
79 fileSourcePath = Path.Combine(directoryPath, fileSourcePath); 106 fileSourcePath = Path.Combine(directoryPath, fileSourcePath);
80 } 107 }
81 108
diff --git a/src/WixToolset.Core/Link/ResolveReferencesCommand.cs b/src/WixToolset.Core/Link/ResolveReferencesCommand.cs
index d2be0699..90b61e8b 100644
--- a/src/WixToolset.Core/Link/ResolveReferencesCommand.cs
+++ b/src/WixToolset.Core/Link/ResolveReferencesCommand.cs
@@ -72,27 +72,22 @@ namespace WixToolset.Core.Link
72 continue; 72 continue;
73 } 73 }
74 74
75 if (!this.symbolsWithSections.TryGetValue(wixSimpleReferenceRow.SymbolicName, out var symbolWithSection)) 75 // See if the symbol (and any of its duplicates) are appropriately accessible.
76 { 76 if (this.symbolsWithSections.TryGetValue(wixSimpleReferenceRow.SymbolicName, out var symbolWithSection))
77 this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName));
78 }
79 else // see if the symbol (and any of its duplicates) are appropriately accessible.
80 { 77 {
81 var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection); 78 var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection);
82 if (!accessible.Any()) 79 if (accessible.Count == 1)
83 {
84 this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbolWithSection.Access));
85 }
86 else if (1 == accessible.Count)
87 { 80 {
88 var accessibleSymbol = accessible[0]; 81 var accessibleSymbol = accessible[0];
89 this.referencedSymbols.Add(accessibleSymbol); 82 if (this.referencedSymbols.Add(accessibleSymbol) && null != accessibleSymbol.Section)
90
91 if (null != accessibleSymbol.Section)
92 { 83 {
93 this.RecursivelyResolveReferences(accessibleSymbol.Section); 84 this.RecursivelyResolveReferences(accessibleSymbol.Section);
94 } 85 }
95 } 86 }
87 else if (accessible.Count == 0)
88 {
89 this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbolWithSection.Access));
90 }
96 else // display errors for the duplicate symbols. 91 else // display errors for the duplicate symbols.
97 { 92 {
98 var accessibleSymbol = accessible[0]; 93 var accessibleSymbol = accessible[0];
@@ -113,6 +108,10 @@ namespace WixToolset.Core.Link
113 } 108 }
114 } 109 }
115 } 110 }
111 else
112 {
113 this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName));
114 }
116 } 115 }
117 } 116 }
118 117
diff --git a/src/WixToolset.Core/Link/SymbolWithSection.cs b/src/WixToolset.Core/Link/SymbolWithSection.cs
new file mode 100644
index 00000000..c8934d0f
--- /dev/null
+++ b/src/WixToolset.Core/Link/SymbolWithSection.cs
@@ -0,0 +1,91 @@
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.Core.Link
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Data;
9
10 /// <summary>
11 /// Symbol with section representing a single unique symbol.
12 /// </summary>
13 internal class SymbolWithSection
14 {
15 private HashSet<SymbolWithSection> possibleConflicts;
16 private HashSet<SymbolWithSection> redundants;
17
18 /// <summary>
19 /// Creates a symbol for a symbol.
20 /// </summary>
21 /// <param name="symbol">Symbol for the symbol</param>
22 public SymbolWithSection(IntermediateSection section, IntermediateSymbol symbol)
23 {
24 this.Symbol = symbol;
25 this.Section = section;
26 this.Name = String.Concat(this.Symbol.Definition.Name, ":", this.Symbol.Id.Id);
27 }
28
29 /// <summary>
30 /// Gets the accessibility of the symbol which is a direct reflection of the accessibility of the row's accessibility.
31 /// </summary>
32 /// <value>Accessbility of the symbol.</value>
33 public AccessModifier Access => this.Symbol.Id.Access;
34
35 /// <summary>
36 /// Gets the name of the symbol.
37 /// </summary>
38 /// <value>Name of the symbol.</value>
39 public string Name { get; }
40
41 /// <summary>
42 /// Gets the symbol for this symbol.
43 /// </summary>
44 /// <value>Symbol for this symbol.</value>
45 public IntermediateSymbol Symbol { get; }
46
47 /// <summary>
48 /// Gets the section for the symbol.
49 /// </summary>
50 /// <value>Section for the symbol.</value>
51 public IntermediateSection Section { get; }
52
53 /// <summary>
54 /// Gets any duplicates of this symbol with sections that are possible conflicts.
55 /// </summary>
56 public IEnumerable<SymbolWithSection> PossiblyConflicts => this.possibleConflicts ?? Enumerable.Empty<SymbolWithSection>();
57
58 /// <summary>
59 /// Gets any duplicates of this symbol with sections that are redundant.
60 /// </summary>
61 public IEnumerable<SymbolWithSection> Redundants => this.redundants ?? Enumerable.Empty<SymbolWithSection>();
62
63 /// <summary>
64 /// Adds a duplicate symbol with sections that is a possible conflict.
65 /// </summary>
66 /// <param name="symbolWithSection">Symbol with section that is a possible conflict of this symbol.</param>
67 public void AddPossibleConflict(SymbolWithSection symbolWithSection)
68 {
69 if (null == this.possibleConflicts)
70 {
71 this.possibleConflicts = new HashSet<SymbolWithSection>();
72 }
73
74 this.possibleConflicts.Add(symbolWithSection);
75 }
76
77 /// <summary>
78 /// Adds a duplicate symbol that is redundant.
79 /// </summary>
80 /// <param name="symbolWithSection">Symbol with section that is redundant of this symbol.</param>
81 public void AddRedundant(SymbolWithSection symbolWithSection)
82 {
83 if (null == this.redundants)
84 {
85 this.redundants = new HashSet<SymbolWithSection>();
86 }
87
88 this.redundants.Add(symbolWithSection);
89 }
90 }
91}
diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs
index cdefa5c7..1cfd085d 100644
--- a/src/WixToolset.Core/Linker.cs
+++ b/src/WixToolset.Core/Linker.cs
@@ -149,13 +149,12 @@ namespace WixToolset.Core
149 throw new WixException(ErrorMessages.MissingEntrySection(this.Context.ExpectedOutputType.ToString())); 149 throw new WixException(ErrorMessages.MissingEntrySection(this.Context.ExpectedOutputType.ToString()));
150 } 150 }
151 151
152 // Add the missing standard action symbols. 152 // Add the missing standard action and directory symbols.
153 this.LoadStandardActions(find.EntrySection, find.SymbolsByName); 153 this.LoadStandardSymbols(find.SymbolsByName);
154 154
155 // Resolve the symbol references to find the set of sections we care about for linking. 155 // Resolve the symbol references to find the set of sections we care about for linking.
156 // Of course, we start with the entry section (that's how it got its name after all). 156 // Of course, we start with the entry section (that's how it got its name after all).
157 var resolve = new ResolveReferencesCommand(this.Messaging, find.EntrySection, find.SymbolsByName); 157 var resolve = new ResolveReferencesCommand(this.Messaging, find.EntrySection, find.SymbolsByName);
158
159 resolve.Execute(); 158 resolve.Execute();
160 159
161 if (this.Messaging.EncounteredError) 160 if (this.Messaging.EncounteredError)
@@ -732,14 +731,14 @@ namespace WixToolset.Core
732#endif 731#endif
733 732
734 /// <summary> 733 /// <summary>
735 /// Load the standard action symbols. 734 /// Load the standard action and directory symbols.
736 /// </summary> 735 /// </summary>
737 /// <param name="symbolsByName">Collection of symbols.</param> 736 /// <param name="symbolsByName">Collection of symbols.</param>
738 private void LoadStandardActions(IntermediateSection section, IDictionary<string, SymbolWithSection> symbolsByName) 737 private void LoadStandardSymbols(IDictionary<string, SymbolWithSection> symbolsByName)
739 { 738 {
740 foreach (var actionSymbol in WindowsInstallerStandard.StandardActions()) 739 foreach (var actionSymbol in WindowsInstallerStandard.StandardActions())
741 { 740 {
742 var symbolWithSection = new SymbolWithSection(section, actionSymbol); 741 var symbolWithSection = new SymbolWithSection(null, actionSymbol);
743 742
744 // If the action's symbol has not already been defined (i.e. overriden by the user), add it now. 743 // If the action's symbol has not already been defined (i.e. overriden by the user), add it now.
745 if (!symbolsByName.ContainsKey(symbolWithSection.Name)) 744 if (!symbolsByName.ContainsKey(symbolWithSection.Name))
@@ -747,6 +746,17 @@ namespace WixToolset.Core
747 symbolsByName.Add(symbolWithSection.Name, symbolWithSection); 746 symbolsByName.Add(symbolWithSection.Name, symbolWithSection);
748 } 747 }
749 } 748 }
749
750 foreach (var directorySymbol in WindowsInstallerStandard.StandardDirectories())
751 {
752 var symbolWithSection = new SymbolWithSection(null, directorySymbol);
753
754 // If the directory's symbol has not already been defined (i.e. overriden by the user), add it now.
755 if (!symbolsByName.ContainsKey(symbolWithSection.Name))
756 {
757 symbolsByName.Add(symbolWithSection.Name, symbolWithSection);
758 }
759 }
750 } 760 }
751 761
752 /// <summary> 762 /// <summary>
diff --git a/src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs b/src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs
new file mode 100644
index 00000000..83f2f2bb
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs
@@ -0,0 +1,89 @@
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 WixToolsetTest.CoreIntegration
4{
5 using System.IO;
6 using System.Linq;
7 using WixBuildTools.TestSupport;
8 using WixToolset.Core.TestPackage;
9 using WixToolset.Data;
10 using Xunit;
11
12 public class DirectoryFixture
13 {
14 [Fact]
15 public void CanGet32bitProgramFiles6432Folder()
16 {
17 var folder = TestData.Get(@"TestData");
18
19 using (var fs = new DisposableFileSystem())
20 {
21 var baseFolder = fs.GetFolder();
22 var intermediateFolder = Path.Combine(baseFolder, "obj");
23 var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
24
25 var result = WixRunner.Execute(new[]
26 {
27 "build",
28 Path.Combine(folder, "Directory", "Empty.wxs"),
29 Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
30 "-bindpath", Path.Combine(folder, "SingleFile", "data"),
31 "-intermediateFolder", intermediateFolder,
32 "-o", msiPath
33 });
34
35 result.AssertSuccess();
36
37 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
38 var section = intermediate.Sections.Single();
39
40 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList();
41 Assert.Equal(new[]
42 {
43 "INSTALLFOLDER",
44 "ProgramFiles6432Folder",
45 "ProgramFilesFolder",
46 "TARGETDIR"
47 }, dirSymbols.Select(d => d.Id.Id).ToArray());
48 }
49 }
50
51 [Fact]
52 public void CanGet64bitProgramFiles6432Folder()
53 {
54 var folder = TestData.Get(@"TestData");
55
56 using (var fs = new DisposableFileSystem())
57 {
58 var baseFolder = fs.GetFolder();
59 var intermediateFolder = Path.Combine(baseFolder, "obj");
60 var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
61
62 var result = WixRunner.Execute(new[]
63 {
64 "build",
65 "-arch", "x64",
66 Path.Combine(folder, "Directory", "Empty.wxs"),
67 Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
68 "-bindpath", Path.Combine(folder, "SingleFile", "data"),
69 "-intermediateFolder", intermediateFolder,
70 "-o", msiPath
71 });
72
73 result.AssertSuccess();
74
75 var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
76 var section = intermediate.Sections.Single();
77
78 var dirSymbols = section.Symbols.OfType<WixToolset.Data.Symbols.DirectorySymbol>().ToList();
79 Assert.Equal(new[]
80 {
81 "INSTALLFOLDER",
82 "ProgramFiles6432Folder",
83 "ProgramFiles64Folder",
84 "TARGETDIR"
85 }, dirSymbols.Select(d => d.Id.Id).ToArray());
86 }
87 }
88 }
89}
diff --git a/src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs b/src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs
index 3ab218d1..4ff7f5f6 100644
--- a/src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs
+++ b/src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs
@@ -365,14 +365,15 @@ namespace WixToolsetTest.CoreIntegration
365 365
366 Assert.True(File.Exists(msiPath)); 366 Assert.True(File.Exists(msiPath));
367 var results = Query.QueryDatabase(msiPath, new[] { "Directory" }); 367 var results = Query.QueryDatabase(msiPath, new[] { "Directory" });
368 Assert.Equal(new[] 368 WixAssert.CompareLineByLine(new[]
369 { 369 {
370 "Directory:DUPLICATENAMEANDSHORTNAME\tINSTALLFOLDER\tduplicat", 370 "Directory:DUPLICATENAMEANDSHORTNAME\tINSTALLFOLDER\tduplicat",
371 "Directory:INSTALLFOLDER\tProgramFilesFolder\toekcr5lq|MsiPackage", 371 "Directory:INSTALLFOLDER\tProgramFiles6432Folder\t1egc1laj|MsiPackage",
372 "Directory:NAMEANDSHORTNAME\tINSTALLFOLDER\tSHORTNAM|NameAndShortName", 372 "Directory:NAMEANDSHORTNAME\tINSTALLFOLDER\tSHORTNAM|NameAndShortName",
373 "Directory:NAMEANDSHORTSOURCENAME\tINSTALLFOLDER\tNAMEASSN|NameAndShortSourceName", 373 "Directory:NAMEANDSHORTSOURCENAME\tINSTALLFOLDER\tNAMEASSN|NameAndShortSourceName",
374 "Directory:NAMEWITHSHORTVALUE\tINSTALLFOLDER\tSHORTVAL", 374 "Directory:NAMEWITHSHORTVALUE\tINSTALLFOLDER\tSHORTVAL",
375 "Directory:ProgramFilesFolder\tTARGETDIR\t.", 375 "Directory:ProgramFiles6432Folder\tProgramFilesFolder\t.",
376 "Directory:ProgramFilesFolder\tTARGETDIR\tPFiles",
376 "Directory:SHORTNAMEANDLONGSOURCENAME\tINSTALLFOLDER\tSHNALSNM:6ukthv5q|ShortNameAndLongSourceName", 377 "Directory:SHORTNAMEANDLONGSOURCENAME\tINSTALLFOLDER\tSHNALSNM:6ukthv5q|ShortNameAndLongSourceName",
377 "Directory:SHORTNAMEONLY\tINSTALLFOLDER\tSHORTONL", 378 "Directory:SHORTNAMEONLY\tINSTALLFOLDER\tSHORTONL",
378 "Directory:SOURCENAME\tINSTALLFOLDER\ts2s5bq-i|NameAndSourceName:dhnqygng|SourceNameWithName", 379 "Directory:SOURCENAME\tINSTALLFOLDER\ts2s5bq-i|NameAndSourceName:dhnqygng|SourceNameWithName",
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/CustomAction/SimpleCustomAction.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/CustomAction/SimpleCustomAction.wxs
new file mode 100644
index 00000000..72d5e4a5
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/CustomAction/SimpleCustomAction.wxs
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <ComponentGroup Id="ProductComponents">
5 <ComponentGroupRef Id="MinimalComponentGroup" />
6 </ComponentGroup>
7
8 <Binary Id="Binary1" SourceFile="test.txt" />
9 <CustomAction Id="Action1" BinaryKey="Binary1" DllEntry="EntryPoint1" />
10
11 <InstallExecuteSequence>
12 <Custom Action="Action1" After="InstallFiles" />
13 </InstallExecuteSequence>
14 </Fragment>
15</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs
index 68386612..c55f4ed0 100644
--- a/src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs
@@ -15,11 +15,13 @@
15 </Row> 15 </Row>
16 </CustomTable> 16 </CustomTable>
17 <Directory Id="TARGETDIR" Name="SourceDir"> 17 <Directory Id="TARGETDIR" Name="SourceDir">
18 <Directory Id="ProgramFilesFolder"> 18 <Directory Id="ProgramFilesFolder" Name="PFiles">
19 <Directory Id="INSTALLFOLDER" Name="MsiPackage" ShortName="oekcr5lq"> 19 <Directory Id="ProgramFiles6432Folder">
20 <Component Id="filcV1yrx0x8wJWj4qMzcH21jwkPko" Guid="{E597A58A-03CB-50D8-93E3-DABA263F233A}" Win64="no"> 20 <Directory Id="INSTALLFOLDER" Name="MsiPackage" ShortName="1egc1laj">
21 <File Id="filcV1yrx0x8wJWj4qMzcH21jwkPko" Name="test.txt" KeyPath="yes" Source="SourceDir\\MsiPackage\test.txt" /> 21 <Component Id="filcV1yrx0x8wJWj4qMzcH21jwkPko" Guid="{E597A58A-03CB-50D8-93E3-DABA263F233A}" Win64="no">
22 </Component> 22 <File Id="filcV1yrx0x8wJWj4qMzcH21jwkPko" Name="test.txt" KeyPath="yes" Source="SourceDir\PFiles\\MsiPackage\test.txt" />
23 </Component>
24 </Directory>
23 </Directory> 25 </Directory>
24 </Directory> 26 </Directory>
25 </Directory> 27 </Directory>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/Directory/Empty.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/Directory/Empty.wxs
new file mode 100644
index 00000000..50cf6850
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/Directory/Empty.wxs
@@ -0,0 +1,6 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER" />
5 </Fragment>
6</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs
index b2f22b7d..5b26091a 100644
--- a/src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs
@@ -11,10 +11,6 @@
11 </Product> 11 </Product>
12 12
13 <Fragment> 13 <Fragment>
14 <Directory Id="TARGETDIR" Name="SourceDir"> 14 <Directory Id="INSTALLFOLDER" Name="ProgramFiles6432Folder:\MsiPackage" />
15 <Directory Id="ProgramFilesFolder">
16 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
17 </Directory>
18 </Directory>
19 </Fragment> 15 </Fragment>
20</Wix> 16</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj b/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
index 15078b8a..601a66e7 100644
--- a/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+++ b/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
@@ -36,6 +36,7 @@
36 <Content Include="TestData\Class\IconIndex0.wxs" CopyToOutputDirectory="PreserveNewest" /> 36 <Content Include="TestData\Class\IconIndex0.wxs" CopyToOutputDirectory="PreserveNewest" />
37 <Content Include="TestData\Class\OldClassTableDef.msi" CopyToOutputDirectory="PreserveNewest" /> 37 <Content Include="TestData\Class\OldClassTableDef.msi" CopyToOutputDirectory="PreserveNewest" />
38 <Content Include="TestData\CopyFile\CopyFile.wxs" CopyToOutputDirectory="PreserveNewest" /> 38 <Content Include="TestData\CopyFile\CopyFile.wxs" CopyToOutputDirectory="PreserveNewest" />
39 <Content Include="TestData\CustomAction\SimpleCustomAction.wxs" CopyToOutputDirectory="PreserveNewest" />
39 <Content Include="TestData\CustomAction\CustomActionCycle.wxs" CopyToOutputDirectory="PreserveNewest" /> 40 <Content Include="TestData\CustomAction\CustomActionCycle.wxs" CopyToOutputDirectory="PreserveNewest" />
40 <Content Include="TestData\CustomAction\UnscheduledCustomAction.wxs" CopyToOutputDirectory="PreserveNewest" /> 41 <Content Include="TestData\CustomAction\UnscheduledCustomAction.wxs" CopyToOutputDirectory="PreserveNewest" />
41 <Content Include="TestData\CustomTable\CustomTable-Expected.wxs" CopyToOutputDirectory="PreserveNewest" /> 42 <Content Include="TestData\CustomTable\CustomTable-Expected.wxs" CopyToOutputDirectory="PreserveNewest" />
@@ -48,6 +49,7 @@
48 <Content Include="TestData\CustomTable\LocalizedCustomTable.en-us.wxl" CopyToOutputDirectory="PreserveNewest" /> 49 <Content Include="TestData\CustomTable\LocalizedCustomTable.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
49 <Content Include="TestData\DefaultDir\DefaultDir.wxs" CopyToOutputDirectory="PreserveNewest" /> 50 <Content Include="TestData\DefaultDir\DefaultDir.wxs" CopyToOutputDirectory="PreserveNewest" />
50 <Content Include="TestData\DialogsInInstallUISequence\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" /> 51 <Content Include="TestData\DialogsInInstallUISequence\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
52 <Content Include="TestData\Directory\Empty.wxs" CopyToOutputDirectory="PreserveNewest" />
51 <Content Include="TestData\EnsureTable\EnsureTable.wxs" CopyToOutputDirectory="PreserveNewest" /> 53 <Content Include="TestData\EnsureTable\EnsureTable.wxs" CopyToOutputDirectory="PreserveNewest" />
52 <Content Include="TestData\Environment\Environment.wxs" CopyToOutputDirectory="PreserveNewest" /> 54 <Content Include="TestData\Environment\Environment.wxs" CopyToOutputDirectory="PreserveNewest" />
53 <Content Include="TestData\ErrorsInUI\data\test.txt" CopyToOutputDirectory="PreserveNewest" /> 55 <Content Include="TestData\ErrorsInUI\data\test.txt" CopyToOutputDirectory="PreserveNewest" />