diff --git a/src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs new file mode 100644 index 000000000..78c853502 --- /dev/null +++ b/src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs @@ -0,0 +1,63 @@ +// 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. + +namespace WixToolset.Core.Link +{ + using System.Collections.Generic; + using System.Linq; + using WixToolset.Data; + using WixToolset.Data.Symbols; + + internal class AddDefaultSymbolsCommand + { + public static readonly string WixStandardInstallFolder = "INSTALLFOLDER"; + public static readonly string WixStandardInstallFolderParent = "ProgramFiles6432Folder"; + public static readonly string WixStandardInstallFolderReference = "Directory:INSTALLFOLDER"; + + public AddDefaultSymbolsCommand(FindEntrySectionAndLoadSymbolsCommand find, List sections) + { + this.Find = find; + this.Sections = sections; + } + + public IntermediateSection EntrySection { get; } + + public IEnumerable Sections { get; } + + public FindEntrySectionAndLoadSymbolsCommand Find { get; } + + public void Execute() + { + var symbols = this.Sections.SelectMany(s => s.Symbols); + var directorySymbols = symbols.OfType(); + var referenceSymbols = symbols.OfType(); + + if (referenceSymbols.Any(s => s.SymbolicName == WixStandardInstallFolderReference) + && !directorySymbols.Any(d => d.Id.Id == WixStandardInstallFolder)) + { + // If there are any INSTALLFOLDER references, add a default one, using the + // first reference as the "canonical" reference for source line numbers. + this.AddSymbol(new DirectorySymbol(null, new Identifier(AccessModifier.Global, WixStandardInstallFolder)) + { + ParentDirectoryRef = WixStandardInstallFolderParent, + Name = "!(bind.Property.Manufacturer) !(bind.Property.ProductName)", + SourceName = ".", + }); + + this.AddSymbol(new WixSimpleReferenceSymbol(null, new Identifier(AccessModifier.Global, WixStandardInstallFolder)) + { + Table = "Directory", + PrimaryKeys = WixStandardInstallFolderParent, + }); + } + } + + private void AddSymbol(IntermediateSymbol symbol) + { + this.Find.EntrySection.AddSymbol(symbol); + + var symbolWithSection = new SymbolWithSection(this.Find.EntrySection, symbol); + var fullName = symbolWithSection.GetFullName(); + this.Find.SymbolsByName.Add(fullName, symbolWithSection); + } + } +} diff --git a/src/wix/WixToolset.Core/Linker.cs b/src/wix/WixToolset.Core/Linker.cs index 0cef88d22..22888dc78 100644 --- a/src/wix/WixToolset.Core/Linker.cs +++ b/src/wix/WixToolset.Core/Linker.cs @@ -126,6 +126,13 @@ public Intermediate Link(ILinkContext context) } } + // Add default symbols that need a bit more intelligence than just being + // included in the standard library. + { + var command = new AddDefaultSymbolsCommand(find, sections); + command.Execute(); + } + // Resolve the symbol references to find the set of sections we care about for linking. // Of course, we start with the entry section (that's how it got its name after all). var resolve = new ResolveReferencesCommand(this.Messaging, find.EntrySection, find.SymbolsByName); diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs index 3f4108cbb..7f019692d 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs @@ -13,6 +13,44 @@ namespace WixToolsetTest.CoreIntegration public class DirectoryFixture { + [Fact] + public void CanGetDefaultInstallFolder() + { + var folder = TestData.Get(@"TestData\SingleFile"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "Package.wxs"), + Path.Combine(folder, "PackageComponents.wxs"), + "-loc", Path.Combine(folder, "Package.en-us.wxl"), + "-bindpath", Path.Combine(folder, "data"), + "-intermediateFolder", intermediateFolder, + "-o", msiPath + }); + + result.AssertSuccess(); + + var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); + var section = intermediate.Sections.Single(); + + var dirSymbols = section.Symbols.OfType().ToList(); + WixAssert.CompareLineByLine(new[] + { + "INSTALLFOLDER:ProgramFiles6432Folder:Example Corporation MsiPackage", + "ProgramFiles6432Folder:ProgramFilesFolder:.", + "ProgramFilesFolder:TARGETDIR:PFiles", + "TARGETDIR::SourceDir" + }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray()); + } + } + [Fact] public void CanGet32bitProgramFiles6432Folder() { diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/MsiFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/MsiFixture.cs index fe9e8641f..7f5dfcd0c 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/MsiFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/MsiFixture.cs @@ -38,7 +38,7 @@ public void CanBuildSingleFile() Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\MsiPackage\test.txt"))); + Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\PFiles\Example Corporation MsiPackage\test.txt"))); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SingleFile/Package.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SingleFile/Package.wxs index 3cab42674..0a5823900 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SingleFile/Package.wxs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SingleFile/Package.wxs @@ -1,17 +1,9 @@ - - - - - - - -