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" />