From 7ce477c6863c74ef0a50d117d8c28b2f19971b42 Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Sat, 29 Jan 2022 23:44:11 -0500 Subject: Add compiler extension to handle platforms. Custom actions to print EULA and validate install directories are defined in WixUIExtension compiler extension, to handle platform-specific custom actions referred to from `DoAction` control events. This is the least-worst solution, given the `DoAction` approach used in the WixUI authoring and anyone customizing a WixUI set. --- src/ext/UI/ca/uica.vcxproj | 16 +++ .../TestData/WixUI_Advanced/Package.wxs | 6 +- .../TestData/WixUI_FeatureTree/Package.wxs | 4 +- .../TestData/WixUI_InstallDir/Package.wxs | 4 +- .../TestData/WixUI_Minimal/Package.wxs | 4 +- .../TestData/WixUI_Mondo/Package.wxs | 4 +- .../test/WixToolsetTest.UI/UIExtensionFixture.cs | 99 +++++++++++------ src/ext/UI/wixext/UICompiler.cs | 118 +++++++++++++++++++++ src/ext/UI/wixext/UIExtensionFactory.cs | 1 + src/ext/UI/wixlib/Common_Platform.wxi | 17 ++- src/ext/UI/wixlib/Common_arm64.wxs | 7 ++ src/ext/UI/wixlib/Common_x64.wxs | 7 ++ src/ext/UI/wixlib/WixUI_Advanced.wxs | 1 - src/ext/UI/wixlib/WixUI_FeatureTree.wxs | 1 - src/ext/UI/wixlib/WixUI_InstallDir.wxs | 1 - src/ext/UI/wixlib/WixUI_Minimal.wxs | 1 - src/ext/UI/wixlib/WixUI_Mondo.wxs | 1 - src/ext/UI/wixlib/caSuffix.wxi | 27 ----- src/ext/UI/wixlib/ui.wixproj | 4 +- 19 files changed, 238 insertions(+), 85 deletions(-) create mode 100644 src/ext/UI/wixext/UICompiler.cs create mode 100644 src/ext/UI/wixlib/Common_arm64.wxs create mode 100644 src/ext/UI/wixlib/Common_x64.wxs delete mode 100644 src/ext/UI/wixlib/caSuffix.wxi (limited to 'src/ext') diff --git a/src/ext/UI/ca/uica.vcxproj b/src/ext/UI/ca/uica.vcxproj index e06b7572..27f0faa7 100644 --- a/src/ext/UI/ca/uica.vcxproj +++ b/src/ext/UI/ca/uica.vcxproj @@ -11,6 +11,22 @@ Release Win32 + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + diff --git a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Advanced/Package.wxs b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Advanced/Package.wxs index 5ce4b00f..c22328e6 100644 --- a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Advanced/Package.wxs +++ b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Advanced/Package.wxs @@ -1,5 +1,5 @@ - - + + @@ -12,7 +12,7 @@ - + diff --git a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_FeatureTree/Package.wxs b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_FeatureTree/Package.wxs index aff1c077..7c4db223 100644 --- a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_FeatureTree/Package.wxs +++ b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_FeatureTree/Package.wxs @@ -1,4 +1,4 @@ - + @@ -12,7 +12,7 @@ - + diff --git a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_InstallDir/Package.wxs b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_InstallDir/Package.wxs index 7c2ceae0..b6f2344a 100644 --- a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_InstallDir/Package.wxs +++ b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_InstallDir/Package.wxs @@ -1,4 +1,4 @@ - + @@ -12,7 +12,7 @@ - + diff --git a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Minimal/Package.wxs b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Minimal/Package.wxs index d2ff256c..962be579 100644 --- a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Minimal/Package.wxs +++ b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Minimal/Package.wxs @@ -1,4 +1,4 @@ - + @@ -12,7 +12,7 @@ - + diff --git a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Mondo/Package.wxs b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Mondo/Package.wxs index 8d5a856a..9eca9790 100644 --- a/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Mondo/Package.wxs +++ b/src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Mondo/Package.wxs @@ -1,4 +1,4 @@ - + @@ -12,7 +12,7 @@ - + diff --git a/src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs b/src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs index 778bfb64..4ab7ec3f 100644 --- a/src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs +++ b/src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs @@ -7,8 +7,6 @@ namespace WixToolsetTest.UI using System.Linq; using WixBuildTools.TestSupport; using WixToolset.Core.TestPackage; - using WixToolset.Data; - using WixToolset.Data.Symbols; using WixToolset.Data.WindowsInstaller; using WixToolset.UI; using Xunit; @@ -22,11 +20,48 @@ namespace WixToolsetTest.UI var bindFolder = TestData.Get(@"TestData\data"); var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); - var results = build.BuildAndQuery(Build, "Property"); - WixAssert.CompareLineByLine(new[] - { - "Property:WixUI_Mode\tAdvanced", - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray()); + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction"); + Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerMachineFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerUserFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerMachineFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerUserFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIPrintEula\t65\tWixUiCa_X86\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIValidatePath\t65\tWixUiCa_X86\t")); + } + + [Fact] + public void CanBuildUsingWixUIAdvancedX64() + { + var folder = TestData.Get(@"TestData\WixUI_Advanced"); + var bindFolder = TestData.Get(@"TestData\data"); + var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); + + var results = build.BuildAndQuery(BuildX64, "Dialog", "CustomAction"); + Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerMachineFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerUserFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerMachineFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerUserFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIPrintEula\t65\tWixUiCa_X64\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIValidatePath\t65\tWixUiCa_X64\t")); + } + + [Fact] + public void CanBuildUsingWixUIAdvancedARM64() + { + var folder = TestData.Get(@"TestData\WixUI_Advanced"); + var bindFolder = TestData.Get(@"TestData\data"); + var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); + + var results = build.BuildAndQuery(BuildARM64, "Dialog", "CustomAction"); + Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerMachineFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerUserFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerMachineFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerUserFolder\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIPrintEula\t65\tWixUiCa_A64\t")); + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIValidatePath\t65\tWixUiCa_A64\t")); } [Fact] @@ -36,11 +71,10 @@ namespace WixToolsetTest.UI var bindFolder = TestData.Get(@"TestData\data"); var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); - var results = build.BuildAndQuery(Build, "Property"); - WixAssert.CompareLineByLine(new[] - { - "Property:WixUI_Mode\tFeatureTree", - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray()); + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction"); + Assert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t")); + Assert.Single(results, result => result.StartsWith("Dialog:CustomizeDlg\t")); + Assert.Empty(results.Where(result => result.StartsWith("Dialog:SetupTypeDlg\t"))); } [Fact] @@ -50,11 +84,8 @@ namespace WixToolsetTest.UI var bindFolder = TestData.Get(@"TestData\data"); var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); - var results = build.BuildAndQuery(Build, "Property"); - WixAssert.CompareLineByLine(new[] - { - "Property:WixUI_Mode\tInstallDir", - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray()); + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction"); + Assert.Single(results, result => result.StartsWith("Dialog:InstallDirDlg\t")); } [Fact] @@ -64,11 +95,8 @@ namespace WixToolsetTest.UI var bindFolder = TestData.Get(@"TestData\data"); var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); - var results = build.BuildAndQuery(Build, "Property"); - WixAssert.CompareLineByLine(new[] - { - "Property:WixUI_Mode\tMinimal", - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray()); + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction"); + Assert.Single(results, result => result.StartsWith("Dialog:WelcomeEulaDlg\t")); } [Fact] @@ -92,10 +120,8 @@ namespace WixToolsetTest.UI }); var wid = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); - var propertyTable = wid.Tables["Property"]; - - var propertyRow = propertyTable.Rows.Single(r => r.GetPrimaryKey() == "WixUI_Mode"); - WixAssert.StringEqual("Minimal", propertyRow.FieldAsString(1)); + var dialogTable = wid.Tables["Dialog"]; + var dialogRow = dialogTable.Rows.Single(r => r.GetPrimaryKey() == "WelcomeEulaDlg"); } } @@ -106,11 +132,10 @@ namespace WixToolsetTest.UI var bindFolder = TestData.Get(@"TestData\data"); var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder }); - var results = build.BuildAndQuery(Build, "Property"); - WixAssert.CompareLineByLine(new[] - { - "Property:WixUI_Mode\tMondo", - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray()); + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction"); + Assert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t")); + Assert.Single(results, result => result.StartsWith("Dialog:CustomizeDlg\t")); + Assert.Single(results, result => result.StartsWith("Dialog:SetupTypeDlg\t")); } [Fact] @@ -133,6 +158,18 @@ namespace WixToolsetTest.UI .AssertSuccess(); } + private static void BuildX64(string[] args) + { + var result = WixRunner.Execute(args.Concat(new[] { "-arch", "x64" }).ToArray()) + .AssertSuccess(); + } + + private static void BuildARM64(string[] args) + { + var result = WixRunner.Execute(args.Concat(new[] { "-arch", "arm64" }).ToArray()) + .AssertSuccess(); + } + private static void BuildInGerman(string[] args) { var localizedArgs = args.Append("-culture").Append("de-DE").ToArray(); diff --git a/src/ext/UI/wixext/UICompiler.cs b/src/ext/UI/wixext/UICompiler.cs new file mode 100644 index 00000000..46b856c0 --- /dev/null +++ b/src/ext/UI/wixext/UICompiler.cs @@ -0,0 +1,118 @@ +// 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.UI +{ + using System; + using System.Collections.Generic; + using System.Xml.Linq; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Extensibility; + + /// + /// The decompiler for the WiX Toolset UI Extension. + /// + public sealed class UICompiler : BaseCompilerExtension + { + public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/ui"; + + /// + /// Processes an element for the Compiler. + /// + /// Source line number for the parent element. + /// Parent element of element to process. + /// Element to process. + /// Extra information about the context in which this element is being parsed. + public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context) + { + switch (parentElement.Name.LocalName) + { + case "Fragment": + case "Module": + case "PatchFamily": + case "Package": + case "UI": + switch (element.Name.LocalName) + { + case "WixUI": + this.ParseWixUIElement(intermediate, section, element); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + } + + /// + /// Parses a WixUI element. + /// + private void ParseWixUIElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string id = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id")); + } + else + { + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixUI, id); + + // Because these custom actions are "scheduled" via `DoAction` control events, we have to create the + // custom action definitions here, so the `DoAction` references are static and the targets are + // dynamically created to properly reflect the platform-specific DLL and avoid having duplicate ids + // in the UI .wixlib. + var platform = this.Context.Platform == Platform.ARM64 ? "A64" : this.Context.Platform.ToString(); + var source = $"WixUiCa_{platform}"; + + section.AddSymbol(new CustomActionSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixUIPrintEula")) + { + TargetType = CustomActionTargetType.Dll, + Target = "PrintEula", + SourceType = CustomActionSourceType.Binary, + Source = source, + IgnoreResult = true, + ExecutionType = CustomActionExecutionType.Immediate, + }); + + section.AddSymbol(new CustomActionSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixUIValidatePath")) + { + TargetType = CustomActionTargetType.Dll, + Target = "ValidatePath", + SourceType = CustomActionSourceType.Binary, + Source = source, + IgnoreResult = true, + ExecutionType = CustomActionExecutionType.Immediate, + }); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + } + } +} diff --git a/src/ext/UI/wixext/UIExtensionFactory.cs b/src/ext/UI/wixext/UIExtensionFactory.cs index 141aa39f..a16a9899 100644 --- a/src/ext/UI/wixext/UIExtensionFactory.cs +++ b/src/ext/UI/wixext/UIExtensionFactory.cs @@ -11,6 +11,7 @@ namespace WixToolset.UI protected override IReadOnlyCollection ExtensionTypes => new[] { typeof(UIExtensionData), + typeof(UICompiler), }; } } diff --git a/src/ext/UI/wixlib/Common_Platform.wxi b/src/ext/UI/wixlib/Common_Platform.wxi index ffaa7114..0c03629c 100644 --- a/src/ext/UI/wixlib/Common_Platform.wxi +++ b/src/ext/UI/wixlib/Common_Platform.wxi @@ -2,18 +2,15 @@ - - - - - + - - - - + - + diff --git a/src/ext/UI/wixlib/Common_arm64.wxs b/src/ext/UI/wixlib/Common_arm64.wxs new file mode 100644 index 00000000..61dd5ddd --- /dev/null +++ b/src/ext/UI/wixlib/Common_arm64.wxs @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ext/UI/wixlib/Common_x64.wxs b/src/ext/UI/wixlib/Common_x64.wxs new file mode 100644 index 00000000..89204605 --- /dev/null +++ b/src/ext/UI/wixlib/Common_x64.wxs @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/ext/UI/wixlib/WixUI_Advanced.wxs b/src/ext/UI/wixlib/WixUI_Advanced.wxs index 7d1f4df0..2ea7a97d 100644 --- a/src/ext/UI/wixlib/WixUI_Advanced.wxs +++ b/src/ext/UI/wixlib/WixUI_Advanced.wxs @@ -53,7 +53,6 @@ Todo: - diff --git a/src/ext/UI/wixlib/WixUI_FeatureTree.wxs b/src/ext/UI/wixlib/WixUI_FeatureTree.wxs index e999f2fe..6f36bdb8 100644 --- a/src/ext/UI/wixlib/WixUI_FeatureTree.wxs +++ b/src/ext/UI/wixlib/WixUI_FeatureTree.wxs @@ -29,7 +29,6 @@ Patch dialog sequence: - diff --git a/src/ext/UI/wixlib/WixUI_InstallDir.wxs b/src/ext/UI/wixlib/WixUI_InstallDir.wxs index afe7820f..f8eb3b11 100644 --- a/src/ext/UI/wixlib/WixUI_InstallDir.wxs +++ b/src/ext/UI/wixlib/WixUI_InstallDir.wxs @@ -30,7 +30,6 @@ Patch dialog sequence: - diff --git a/src/ext/UI/wixlib/WixUI_Minimal.wxs b/src/ext/UI/wixlib/WixUI_Minimal.wxs index 08dba96d..8ac9751f 100644 --- a/src/ext/UI/wixlib/WixUI_Minimal.wxs +++ b/src/ext/UI/wixlib/WixUI_Minimal.wxs @@ -24,7 +24,6 @@ Patch dialog sequence: - diff --git a/src/ext/UI/wixlib/WixUI_Mondo.wxs b/src/ext/UI/wixlib/WixUI_Mondo.wxs index 2d53b9dd..6a4b15b1 100644 --- a/src/ext/UI/wixlib/WixUI_Mondo.wxs +++ b/src/ext/UI/wixlib/WixUI_Mondo.wxs @@ -31,7 +31,6 @@ Patch dialog sequence: - diff --git a/src/ext/UI/wixlib/caSuffix.wxi b/src/ext/UI/wixlib/caSuffix.wxi deleted file mode 100644 index 18436269..00000000 --- a/src/ext/UI/wixlib/caSuffix.wxi +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/ext/UI/wixlib/ui.wixproj b/src/ext/UI/wixlib/ui.wixproj index 2b335f01..ead77af4 100644 --- a/src/ext/UI/wixlib/ui.wixproj +++ b/src/ext/UI/wixlib/ui.wixproj @@ -27,7 +27,9 @@ - + + + -- cgit v1.2.3-55-g6feb