@joebigelow / wix-1 / commits / b62a7a0b

Support implicit standard directory reference and "3264" platform folders

Completes wixtoolset/issues#5798 and wixtoolset/issues#5835

Rob Mensching committed Jul 21, 2020 at 14:31 UTC b62a7a0beb7ceb7987de28ec768c7814cadb83b9
17 files changed +437 -72
src/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs new
+95
@@ -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 +
3 +namespace 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 +}
src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+8 -1
@@ -133,6 +133,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
133 bool compressed;
134 bool longNames;
135 int installerVersion;
136 + Platform platform;
137 string modularizationSuffix;
138 {
139 var command = new BindSummaryInfoCommand(section);
@@ -141,6 +142,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
142 compressed = command.Compressed;
143 longNames = command.LongNames;
144 installerVersion = command.InstallerVersion;
145 + platform = command.Platform;
146 modularizationSuffix = command.ModularizationSuffix;
147 }
148
@@ -193,6 +195,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
195 command.Execute();
196 }
197
198 + {
199 + var command = new AddRequiredStandardDirectories(section, platform);
200 + command.Execute();
201 + }
202 +
203 {
204 var command = new CreateSpecialPropertiesCommand(section);
205 command.Execute();
@@ -332,7 +339,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
339
340 // Set generated component guids.
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);
343 command.Execute();
344 }
345
src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
+31
@@ -32,6 +32,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
32
33 public int InstallerVersion { get; private set; }
34
35 + public Platform Platform { get; private set; }
36 +
37 /// <summary>
38 /// Modularization guid, or null if the output is not a module.
39 /// </summary>
@@ -66,6 +68,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
68 summaryInformationSymbol.Value = Common.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture);
69 }
70 break;
71 + case SummaryInformationType.PlatformAndLanguage:
72 + this.Platform = GetPlatformFromSummaryInformation(summaryInformationSymbol.Value);
73 + break;
74 +
75 case SummaryInformationType.PackageCode: // PID_REVNUMBER
76 var packageCode = summaryInformationSymbol.Value;
77
@@ -137,5 +143,30 @@ namespace WixToolset.Core.WindowsInstaller.Bind
143 });
144 }
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 + }
171 }
172 }
src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
+6 -3
@@ -16,12 +16,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
16 /// </summary>
17 internal class CalculateComponentGuids
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 {
21 this.Messaging = messaging;
22 this.BackendHelper = helper;
23 this.PathResolver = pathResolver;
24 this.Section = section;
25 + this.Platform = platform;
26 }
27
28 private IMessaging Messaging { get; }
@@ -32,6 +33,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
33
34 private IntermediateSection Section { get; }
35
36 + private Platform Platform { get; }
37 +
38 public void Execute()
39 {
40 Dictionary<string, RegistrySymbol> registryKeyRows = null;
@@ -42,7 +45,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
45 // Find components with generatable guids.
46 foreach (var componentSymbol in this.Section.Symbols.OfType<ComponentSymbol>())
47 {
45 - // Skip components that do not specify generate guid.
48 + // Skip components that do not specify generate guid.
49 if (componentSymbol.ComponentId != "*")
50 {
51 continue;
@@ -135,7 +138,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
138 if (fileRow.Id.Id == componentSymbol.KeyPath)
139 {
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);
142 string fileName = Common.GetName(fileRow.Name, false, true).ToLowerInvariant();
143 path = Path.Combine(directoryPath, fileName);
144
src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs
+14 -22
@@ -34,25 +34,25 @@ namespace WixToolset.Core.WindowsInstaller.Bind
34 {
35 var requiredActionSymbols = new Dictionary<string, WixActionSymbol>();
36
37 - // Get the standard actions required based on symbols in the section.
38 - var overridableActionSymbols = this.GetRequiredStandardActions();
39 -
37 // Index all the action symbols and look for collisions.
38 foreach (var actionSymbol in this.Section.Symbols.OfType<WixActionSymbol>())
39 {
40 if (actionSymbol.Overridable) // overridable action
41 {
45 - if (overridableActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol))
42 + if (requiredActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol))
43 {
47 - this.Messaging.Write(ErrorMessages.OverridableActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action));
48 - if (null != collidingActionSymbol.SourceLineNumbers)
44 + if (collidingActionSymbol.Overridable)
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 }
52 }
53 else
54 {
55 - overridableActionSymbols.Add(actionSymbol.Id.Id, actionSymbol);
55 + requiredActionSymbols.Add(actionSymbol.Id.Id, actionSymbol);
56 }
57 }
58 else // unsequenced or sequenced action.
@@ -71,7 +71,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
71 }
72 }
73
74 - if (requiredActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol))
74 + if (requiredActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol) && !collidingActionSymbol.Overridable)
75 {
76 this.Messaging.Write(ErrorMessages.ActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action));
77 if (null != collidingActionSymbol.SourceLineNumbers)
@@ -81,13 +81,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
81 }
82 else
83 {
84 - requiredActionSymbols.Add(actionSymbol.Id.Id, actionSymbol);
84 + requiredActionSymbols[actionSymbol.Id.Id] = actionSymbol;
85 }
86 }
87 }
88
89 + // Get the standard actions required based on symbols in the section.
90 + var requiredStandardActions = this.GetRequiredStandardActions();
91 +
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)
94 {
95 if (!requiredActionSymbols.ContainsKey(actionSymbol.Id.Id))
96 {
@@ -557,17 +560,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
560 return set;
561 }
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 -
563 /// <summary>
564 /// Sequence an action before or after a standard action.
565 /// </summary>
src/WixToolset.Core/Compiler.cs
+1 -2
@@ -4279,8 +4279,7 @@ namespace WixToolset.Core
4279 this.Core.AddInlineDirectoryId(inlineSyntax, id.Id);
4280 }
4281 }
4282 -
4283 - if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !("SourceDir".Equals(name, StringComparison.Ordinal) && shortName == null && shortSourceName == null && sourceName == null))
4282 + else if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !("SourceDir".Equals(name, StringComparison.Ordinal) && shortName == null && shortSourceName == null && sourceName == null))
4283 {
4284 this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, name));
4285 }
src/WixToolset.Core/ExtensibilityServices/PathResolver.cs
+39 -12
@@ -12,7 +12,7 @@ namespace WixToolset.Core.ExtensibilityServices
12
13 internal class PathResolver : IPathResolver
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 {
17 if (!directories.TryGetValue(directory, out var resolvedDirectory))
18 {
@@ -25,19 +25,13 @@ namespace WixToolset.Core.ExtensibilityServices
25 {
26 resolvedDirectory.Path = componentIdGenSeeds[directory];
27 }
28 - else if (canonicalize && WindowsInstallerStandard.IsStandardDirectory(directory))
28 + else if (WindowsInstallerStandard.IsStandardDirectory(directory))
29 {
30 - // when canonicalization is on, standard directories are treated equally
31 - resolvedDirectory.Path = directory;
30 + resolvedDirectory.Path = WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directory, platform);
31 }
32 else
33 {
35 - string name = resolvedDirectory.Name;
36 -
37 - if (canonicalize)
38 - {
39 - name = name?.ToLowerInvariant();
40 - }
34 + var name = resolvedDirectory.Name?.ToLowerInvariant();
35
36 if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent))
37 {
@@ -45,7 +39,7 @@ namespace WixToolset.Core.ExtensibilityServices
39 }
40 else
41 {
48 - var parentPath = this.GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize);
42 + var parentPath = this.GetCanonicalDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, platform);
43
44 if (null != resolvedDirectory.Name)
45 {
@@ -62,6 +56,39 @@ namespace WixToolset.Core.ExtensibilityServices
56 return resolvedDirectory.Path;
57 }
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 +
92 public string GetFileSourcePath(Dictionary<string, IResolvedDirectory> directories, string directoryId, string fileName, bool compressed, bool useLongName)
93 {
94 var fileSourcePath = Common.GetName(fileName, true, useLongName);
@@ -75,7 +102,7 @@ namespace WixToolset.Core.ExtensibilityServices
102 {
103 // Get the relative path of where we want the file to be layed out as specified
104 // in the Directory table.
78 - var directoryPath = this.GetDirectoryPath(directories, null, directoryId, false);
105 + var directoryPath = this.GetDirectoryPath(directories, directoryId);
106 fileSourcePath = Path.Combine(directoryPath, fileSourcePath);
107 }
108
src/WixToolset.Core/Link/ResolveReferencesCommand.cs
+12 -13
@@ -72,27 +72,22 @@ namespace WixToolset.Core.Link
72 continue;
73 }
74
75 - if (!this.symbolsWithSections.TryGetValue(wixSimpleReferenceRow.SymbolicName, out var symbolWithSection))
76 - {
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.
75 + // See if the symbol (and any of its duplicates) are appropriately accessible.
76 + if (this.symbolsWithSections.TryGetValue(wixSimpleReferenceRow.SymbolicName, out var symbolWithSection))
77 {
78 var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection);
82 - if (!accessible.Any())
83 - {
84 - this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbolWithSection.Access));
85 - }
86 - else if (1 == accessible.Count)
79 + if (accessible.Count == 1)
80 {
81 var accessibleSymbol = accessible[0];
89 - this.referencedSymbols.Add(accessibleSymbol);
90 -
91 - if (null != accessibleSymbol.Section)
82 + if (this.referencedSymbols.Add(accessibleSymbol) && null != accessibleSymbol.Section)
83 {
84 this.RecursivelyResolveReferences(accessibleSymbol.Section);
85 }
86 }
87 + else if (accessible.Count == 0)
88 + {
89 + this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbolWithSection.Access));
90 + }
91 else // display errors for the duplicate symbols.
92 {
93 var accessibleSymbol = accessible[0];
@@ -113,6 +108,10 @@ namespace WixToolset.Core.Link
108 }
109 }
110 }
111 + else
112 + {
113 + this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName));
114 + }
115 }
116 }
117
src/WixToolset.Core/Link/SymbolWithSection.cs new
+91
@@ -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 +
3 +namespace 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 +}
src/WixToolset.Core/Linker.cs
+16 -6
@@ -149,13 +149,12 @@ namespace WixToolset.Core
149 throw new WixException(ErrorMessages.MissingEntrySection(this.Context.ExpectedOutputType.ToString()));
150 }
151
152 - // Add the missing standard action symbols.
153 - this.LoadStandardActions(find.EntrySection, find.SymbolsByName);
152 + // Add the missing standard action and directory symbols.
153 + this.LoadStandardSymbols(find.SymbolsByName);
154
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).
157 var resolve = new ResolveReferencesCommand(this.Messaging, find.EntrySection, find.SymbolsByName);
158 -
158 resolve.Execute();
159
160 if (this.Messaging.EncounteredError)
@@ -732,14 +731,14 @@ namespace WixToolset.Core
731 #endif
732
733 /// <summary>
735 - /// Load the standard action symbols.
734 + /// Load the standard action and directory symbols.
735 /// </summary>
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)
738 {
739 foreach (var actionSymbol in WindowsInstallerStandard.StandardActions())
740 {
742 - var symbolWithSection = new SymbolWithSection(section, actionSymbol);
741 + var symbolWithSection = new SymbolWithSection(null, actionSymbol);
742
743 // If the action's symbol has not already been defined (i.e. overriden by the user), add it now.
744 if (!symbolsByName.ContainsKey(symbolWithSection.Name))
@@ -747,6 +746,17 @@ namespace WixToolset.Core
746 symbolsByName.Add(symbolWithSection.Name, symbolWithSection);
747 }
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 + }
760 }
761
762 /// <summary>
src/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs new
+89
@@ -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 +
3 +namespace 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 +}
src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs
+4 -3
@@ -365,14 +365,15 @@ namespace WixToolsetTest.CoreIntegration
365
366 Assert.True(File.Exists(msiPath));
367 var results = Query.QueryDatabase(msiPath, new[] { "Directory" });
368 - Assert.Equal(new[]
368 + WixAssert.CompareLineByLine(new[]
369 {
370 "Directory:DUPLICATENAMEANDSHORTNAME\tINSTALLFOLDER\tduplicat",
371 - "Directory:INSTALLFOLDER\tProgramFilesFolder\toekcr5lq|MsiPackage",
371 + "Directory:INSTALLFOLDER\tProgramFiles6432Folder\t1egc1laj|MsiPackage",
372 "Directory:NAMEANDSHORTNAME\tINSTALLFOLDER\tSHORTNAM|NameAndShortName",
373 "Directory:NAMEANDSHORTSOURCENAME\tINSTALLFOLDER\tNAMEASSN|NameAndShortSourceName",
374 "Directory:NAMEWITHSHORTVALUE\tINSTALLFOLDER\tSHORTVAL",
375 - "Directory:ProgramFilesFolder\tTARGETDIR\t.",
375 + "Directory:ProgramFiles6432Folder\tProgramFilesFolder\t.",
376 + "Directory:ProgramFilesFolder\tTARGETDIR\tPFiles",
377 "Directory:SHORTNAMEANDLONGSOURCENAME\tINSTALLFOLDER\tSHNALSNM:6ukthv5q|ShortNameAndLongSourceName",
378 "Directory:SHORTNAMEONLY\tINSTALLFOLDER\tSHORTONL",
379 "Directory:SOURCENAME\tINSTALLFOLDER\ts2s5bq-i|NameAndSourceName:dhnqygng|SourceNameWithName",
src/test/WixToolsetTest.CoreIntegration/TestData/CustomAction/SimpleCustomAction.wxs new
+15
@@ -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>
src/test/WixToolsetTest.CoreIntegration/TestData/CustomTable/CustomTable-Expected.wxs
+7 -5
@@ -15,11 +15,13 @@
15 </Row>
16 </CustomTable>
17 <Directory Id="TARGETDIR" Name="SourceDir">
18 - <Directory Id="ProgramFilesFolder">
19 - <Directory Id="INSTALLFOLDER" Name="MsiPackage" ShortName="oekcr5lq">
20 - <Component Id="filcV1yrx0x8wJWj4qMzcH21jwkPko" Guid="{E597A58A-03CB-50D8-93E3-DABA263F233A}" Win64="no">
21 - <File Id="filcV1yrx0x8wJWj4qMzcH21jwkPko" Name="test.txt" KeyPath="yes" Source="SourceDir\\MsiPackage\test.txt" />
22 - </Component>
18 + <Directory Id="ProgramFilesFolder" Name="PFiles">
19 + <Directory Id="ProgramFiles6432Folder">
20 + <Directory Id="INSTALLFOLDER" Name="MsiPackage" ShortName="1egc1laj">
21 + <Component Id="filcV1yrx0x8wJWj4qMzcH21jwkPko" Guid="{E597A58A-03CB-50D8-93E3-DABA263F233A}" Win64="no">
22 + <File Id="filcV1yrx0x8wJWj4qMzcH21jwkPko" Name="test.txt" KeyPath="yes" Source="SourceDir\PFiles\\MsiPackage\test.txt" />
23 + </Component>
24 + </Directory>
25 </Directory>
26 </Directory>
27 </Directory>
src/test/WixToolsetTest.CoreIntegration/TestData/Directory/Empty.wxs new
+6
@@ -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>
src/test/WixToolsetTest.CoreIntegration/TestData/ProductWithComponentGroupRef/Product.wxs
+1 -5
@@ -11,10 +11,6 @@
11 </Product>
12
13 <Fragment>
14 - <Directory Id="TARGETDIR" Name="SourceDir">
15 - <Directory Id="ProgramFilesFolder">
16 - <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
17 - </Directory>
18 - </Directory>
14 + <Directory Id="INSTALLFOLDER" Name="ProgramFiles6432Folder:\MsiPackage" />
15 </Fragment>
16 </Wix>
src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+2
@@ -36,6 +36,7 @@
36 <Content Include="TestData\Class\IconIndex0.wxs" CopyToOutputDirectory="PreserveNewest" />
37 <Content Include="TestData\Class\OldClassTableDef.msi" CopyToOutputDirectory="PreserveNewest" />
38 <Content Include="TestData\CopyFile\CopyFile.wxs" CopyToOutputDirectory="PreserveNewest" />
39 + <Content Include="TestData\CustomAction\SimpleCustomAction.wxs" CopyToOutputDirectory="PreserveNewest" />
40 <Content Include="TestData\CustomAction\CustomActionCycle.wxs" CopyToOutputDirectory="PreserveNewest" />
41 <Content Include="TestData\CustomAction\UnscheduledCustomAction.wxs" CopyToOutputDirectory="PreserveNewest" />
42 <Content Include="TestData\CustomTable\CustomTable-Expected.wxs" CopyToOutputDirectory="PreserveNewest" />
@@ -48,6 +49,7 @@
49 <Content Include="TestData\CustomTable\LocalizedCustomTable.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
50 <Content Include="TestData\DefaultDir\DefaultDir.wxs" CopyToOutputDirectory="PreserveNewest" />
51 <Content Include="TestData\DialogsInInstallUISequence\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
52 + <Content Include="TestData\Directory\Empty.wxs" CopyToOutputDirectory="PreserveNewest" />
53 <Content Include="TestData\EnsureTable\EnsureTable.wxs" CopyToOutputDirectory="PreserveNewest" />
54 <Content Include="TestData\Environment\Environment.wxs" CopyToOutputDirectory="PreserveNewest" />
55 <Content Include="TestData\ErrorsInUI\data\test.txt" CopyToOutputDirectory="PreserveNewest" />