@joebigelow / wix / commits / 7ce477c6

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.

Bob Arnson committed Jan 29, 2022 at 23:44 UTC 7ce477c6863c74ef0a50d117d8c28b2f19971b42
27 files changed +327 -106
src/ext/UI/ca/uica.vcxproj
+16
@@ -11,6 +11,22 @@
11 <Configuration>Release</Configuration>
12 <Platform>Win32</Platform>
13 </ProjectConfiguration>
14 + <ProjectConfiguration Include="Debug|x64">
15 + <Configuration>Debug</Configuration>
16 + <Platform>x64</Platform>
17 + </ProjectConfiguration>
18 + <ProjectConfiguration Include="Release|x64">
19 + <Configuration>Release</Configuration>
20 + <Platform>x64</Platform>
21 + </ProjectConfiguration>
22 + <ProjectConfiguration Include="Debug|ARM64">
23 + <Configuration>Debug</Configuration>
24 + <Platform>ARM64</Platform>
25 + </ProjectConfiguration>
26 + <ProjectConfiguration Include="Release|ARM64">
27 + <Configuration>Release</Configuration>
28 + <Platform>ARM64</Platform>
29 + </ProjectConfiguration>
30 </ItemGroup>
31
32 <PropertyGroup Label="Globals">
src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Advanced/Package.wxs
+3 -3
@@ -1,5 +1,5 @@
1 -<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 - <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" InstallerVersion="200">
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
2 + <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
4
5 <Feature Id="ProductFeature" Title="MsiPackage">
@@ -12,7 +12,7 @@
12 </Component>
13 </ComponentGroup>
14
15 - <UIRef Id="WixUI_Advanced" />
15 + <ui:WixUI Id="WixUI_Advanced" />
16 <Property Id="ApplicationFolderName" Value="MyProgram" />
17 <Property Id="WixAppFolder" Value="WixPerMachineFolder" />
18 </Package>
src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_FeatureTree/Package.wxs
+2 -2
@@ -1,4 +1,4 @@
1 -<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" InstallerVersion="200">
3 <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
4
@@ -12,7 +12,7 @@
12 </Component>
13 </ComponentGroup>
14
15 - <UIRef Id="WixUI_FeatureTree" />
15 + <ui:WixUI Id="WixUI_FeatureTree" />
16 </Package>
17
18 <Fragment>
src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_InstallDir/Package.wxs
+2 -2
@@ -1,4 +1,4 @@
1 -<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" InstallerVersion="200">
3 <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
4
@@ -12,7 +12,7 @@
12 </Component>
13 </ComponentGroup>
14
15 - <UIRef Id="WixUI_InstallDir" />
15 + <ui:WixUI Id="WixUI_InstallDir" />
16 </Package>
17
18 <Fragment>
src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Minimal/Package.wxs
+2 -2
@@ -1,4 +1,4 @@
1 -<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" InstallerVersion="200">
3 <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
4
@@ -12,7 +12,7 @@
12 </Component>
13 </ComponentGroup>
14
15 - <UIRef Id="WixUI_Minimal" />
15 + <ui:WixUI Id="WixUI_Minimal" />
16 </Package>
17
18 <Fragment>
src/ext/UI/test/WixToolsetTest.UI/TestData/WixUI_Mondo/Package.wxs
+2 -2
@@ -1,4 +1,4 @@
1 -<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" InstallerVersion="200">
3 <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
4
@@ -12,7 +12,7 @@
12 </Component>
13 </ComponentGroup>
14
15 - <UIRef Id="WixUI_Mondo" />
15 + <ui:WixUI Id="WixUI_Mondo" />
16 </Package>
17
18 <Fragment>
src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs
+68 -31
@@ -7,8 +7,6 @@ namespace WixToolsetTest.UI
7 using System.Linq;
8 using WixBuildTools.TestSupport;
9 using WixToolset.Core.TestPackage;
10 - using WixToolset.Data;
11 - using WixToolset.Data.Symbols;
10 using WixToolset.Data.WindowsInstaller;
11 using WixToolset.UI;
12 using Xunit;
@@ -22,11 +20,48 @@ namespace WixToolsetTest.UI
20 var bindFolder = TestData.Get(@"TestData\data");
21 var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder });
22
25 - var results = build.BuildAndQuery(Build, "Property");
26 - WixAssert.CompareLineByLine(new[]
27 - {
28 - "Property:WixUI_Mode\tAdvanced",
29 - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray());
23 + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction");
24 + Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t"));
25 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerMachineFolder\t"));
26 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerUserFolder\t"));
27 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerMachineFolder\t"));
28 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerUserFolder\t"));
29 + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIPrintEula\t65\tWixUiCa_X86\t"));
30 + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIValidatePath\t65\tWixUiCa_X86\t"));
31 + }
32 +
33 + [Fact]
34 + public void CanBuildUsingWixUIAdvancedX64()
35 + {
36 + var folder = TestData.Get(@"TestData\WixUI_Advanced");
37 + var bindFolder = TestData.Get(@"TestData\data");
38 + var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder });
39 +
40 + var results = build.BuildAndQuery(BuildX64, "Dialog", "CustomAction");
41 + Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t"));
42 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerMachineFolder\t"));
43 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerUserFolder\t"));
44 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerMachineFolder\t"));
45 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerUserFolder\t"));
46 + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIPrintEula\t65\tWixUiCa_X64\t"));
47 + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIValidatePath\t65\tWixUiCa_X64\t"));
48 + }
49 +
50 + [Fact]
51 + public void CanBuildUsingWixUIAdvancedARM64()
52 + {
53 + var folder = TestData.Get(@"TestData\WixUI_Advanced");
54 + var bindFolder = TestData.Get(@"TestData\data");
55 + var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder });
56 +
57 + var results = build.BuildAndQuery(BuildARM64, "Dialog", "CustomAction");
58 + Assert.Single(results, result => result.StartsWith("Dialog:AdvancedWelcomeEulaDlg\t"));
59 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerMachineFolder\t"));
60 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetDefaultPerUserFolder\t"));
61 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerMachineFolder\t"));
62 + Assert.Single(results, result => result.StartsWith("CustomAction:WixSetPerUserFolder\t"));
63 + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIPrintEula\t65\tWixUiCa_A64\t"));
64 + Assert.Single(results, result => result.StartsWith("CustomAction:WixUIValidatePath\t65\tWixUiCa_A64\t"));
65 }
66
67 [Fact]
@@ -36,11 +71,10 @@ namespace WixToolsetTest.UI
71 var bindFolder = TestData.Get(@"TestData\data");
72 var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder });
73
39 - var results = build.BuildAndQuery(Build, "Property");
40 - WixAssert.CompareLineByLine(new[]
41 - {
42 - "Property:WixUI_Mode\tFeatureTree",
43 - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray());
74 + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction");
75 + Assert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t"));
76 + Assert.Single(results, result => result.StartsWith("Dialog:CustomizeDlg\t"));
77 + Assert.Empty(results.Where(result => result.StartsWith("Dialog:SetupTypeDlg\t")));
78 }
79
80 [Fact]
@@ -50,11 +84,8 @@ namespace WixToolsetTest.UI
84 var bindFolder = TestData.Get(@"TestData\data");
85 var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder });
86
53 - var results = build.BuildAndQuery(Build, "Property");
54 - WixAssert.CompareLineByLine(new[]
55 - {
56 - "Property:WixUI_Mode\tInstallDir",
57 - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray());
87 + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction");
88 + Assert.Single(results, result => result.StartsWith("Dialog:InstallDirDlg\t"));
89 }
90
91 [Fact]
@@ -64,11 +95,8 @@ namespace WixToolsetTest.UI
95 var bindFolder = TestData.Get(@"TestData\data");
96 var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder });
97
67 - var results = build.BuildAndQuery(Build, "Property");
68 - WixAssert.CompareLineByLine(new[]
69 - {
70 - "Property:WixUI_Mode\tMinimal",
71 - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray());
98 + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction");
99 + Assert.Single(results, result => result.StartsWith("Dialog:WelcomeEulaDlg\t"));
100 }
101
102 [Fact]
@@ -92,10 +120,8 @@ namespace WixToolsetTest.UI
120 });
121
122 var wid = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb"));
95 - var propertyTable = wid.Tables["Property"];
96 -
97 - var propertyRow = propertyTable.Rows.Single(r => r.GetPrimaryKey() == "WixUI_Mode");
98 - WixAssert.StringEqual("Minimal", propertyRow.FieldAsString(1));
123 + var dialogTable = wid.Tables["Dialog"];
124 + var dialogRow = dialogTable.Rows.Single(r => r.GetPrimaryKey() == "WelcomeEulaDlg");
125 }
126 }
127
@@ -106,11 +132,10 @@ namespace WixToolsetTest.UI
132 var bindFolder = TestData.Get(@"TestData\data");
133 var build = new Builder(folder, typeof(UIExtensionFactory), new[] { bindFolder });
134
109 - var results = build.BuildAndQuery(Build, "Property");
110 - WixAssert.CompareLineByLine(new[]
111 - {
112 - "Property:WixUI_Mode\tMondo",
113 - }, results.Where(s => s.StartsWith("Property:WixUI_Mode")).ToArray());
135 + var results = build.BuildAndQuery(Build, "Dialog", "CustomAction");
136 + Assert.Single(results, result => result.StartsWith("Dialog:WelcomeDlg\t"));
137 + Assert.Single(results, result => result.StartsWith("Dialog:CustomizeDlg\t"));
138 + Assert.Single(results, result => result.StartsWith("Dialog:SetupTypeDlg\t"));
139 }
140
141 [Fact]
@@ -133,6 +158,18 @@ namespace WixToolsetTest.UI
158 .AssertSuccess();
159 }
160
161 + private static void BuildX64(string[] args)
162 + {
163 + var result = WixRunner.Execute(args.Concat(new[] { "-arch", "x64" }).ToArray())
164 + .AssertSuccess();
165 + }
166 +
167 + private static void BuildARM64(string[] args)
168 + {
169 + var result = WixRunner.Execute(args.Concat(new[] { "-arch", "arm64" }).ToArray())
170 + .AssertSuccess();
171 + }
172 +
173 private static void BuildInGerman(string[] args)
174 {
175 var localizedArgs = args.Append("-culture").Append("de-DE").ToArray();
src/ext/UI/wixext/UICompiler.cs new
+118
@@ -0,0 +1,118 @@
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.UI
4 +{
5 + using System;
6 + using System.Collections.Generic;
7 + using System.Xml.Linq;
8 + using WixToolset.Data;
9 + using WixToolset.Data.Symbols;
10 + using WixToolset.Extensibility;
11 +
12 + /// <summary>
13 + /// The decompiler for the WiX Toolset UI Extension.
14 + /// </summary>
15 + public sealed class UICompiler : BaseCompilerExtension
16 + {
17 + public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/ui";
18 +
19 + /// <summary>
20 + /// Processes an element for the Compiler.
21 + /// </summary>
22 + /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
23 + /// <param name="parentElement">Parent element of element to process.</param>
24 + /// <param name="element">Element to process.</param>
25 + /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
26 + public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
27 + {
28 + switch (parentElement.Name.LocalName)
29 + {
30 + case "Fragment":
31 + case "Module":
32 + case "PatchFamily":
33 + case "Package":
34 + case "UI":
35 + switch (element.Name.LocalName)
36 + {
37 + case "WixUI":
38 + this.ParseWixUIElement(intermediate, section, element);
39 + break;
40 + default:
41 + this.ParseHelper.UnexpectedElement(parentElement, element);
42 + break;
43 + }
44 + break;
45 + default:
46 + this.ParseHelper.UnexpectedElement(parentElement, element);
47 + break;
48 + }
49 + }
50 +
51 + /// <summary>
52 + /// Parses a WixUI element.
53 + /// </summary>
54 + private void ParseWixUIElement(Intermediate intermediate, IntermediateSection section, XElement element)
55 + {
56 + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
57 + string id = null;
58 +
59 + foreach (var attrib in element.Attributes())
60 + {
61 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
62 + {
63 + switch (attrib.Name.LocalName)
64 + {
65 + case "Id":
66 + id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
67 + break;
68 + default:
69 + this.ParseHelper.UnexpectedAttribute(element, attrib);
70 + break;
71 + }
72 + }
73 + else
74 + {
75 + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
76 + }
77 + }
78 +
79 + if (null == id)
80 + {
81 + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
82 + }
83 + else
84 + {
85 + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixUI, id);
86 +
87 + // Because these custom actions are "scheduled" via `DoAction` control events, we have to create the
88 + // custom action definitions here, so the `DoAction` references are static and the targets are
89 + // dynamically created to properly reflect the platform-specific DLL and avoid having duplicate ids
90 + // in the UI .wixlib.
91 + var platform = this.Context.Platform == Platform.ARM64 ? "A64" : this.Context.Platform.ToString();
92 + var source = $"WixUiCa_{platform}";
93 +
94 + section.AddSymbol(new CustomActionSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixUIPrintEula"))
95 + {
96 + TargetType = CustomActionTargetType.Dll,
97 + Target = "PrintEula",
98 + SourceType = CustomActionSourceType.Binary,
99 + Source = source,
100 + IgnoreResult = true,
101 + ExecutionType = CustomActionExecutionType.Immediate,
102 + });
103 +
104 + section.AddSymbol(new CustomActionSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixUIValidatePath"))
105 + {
106 + TargetType = CustomActionTargetType.Dll,
107 + Target = "ValidatePath",
108 + SourceType = CustomActionSourceType.Binary,
109 + Source = source,
110 + IgnoreResult = true,
111 + ExecutionType = CustomActionExecutionType.Immediate,
112 + });
113 + }
114 +
115 + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
116 + }
117 + }
118 +}
src/ext/UI/wixext/UIExtensionFactory.cs
+1
@@ -11,6 +11,7 @@ namespace WixToolset.UI
11 protected override IReadOnlyCollection<Type> ExtensionTypes => new[]
12 {
13 typeof(UIExtensionData),
14 + typeof(UICompiler),
15 };
16 }
17 }
src/ext/UI/wixlib/Common_Platform.wxi
+7 -10
@@ -2,18 +2,15 @@
2
3
4 <Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 - <?include caSuffix.wxi ?>
6 - <Fragment>
7 - <!-- print EULA functionality -->
8 - <CustomAction Id="WixUIPrintEula$(var.Suffix)" DllEntry="PrintEula" Return="ignore" Execute="immediate" BinaryRef="WixUIWixca$(var.Suffix)" />
9 - </Fragment>
5 + <?include ..\..\caDecor.wxi ?>
6
11 - <Fragment>
12 - <!-- Validate install directory -->
13 - <CustomAction Id="WixUIValidatePath$(var.Suffix)" DllEntry="ValidatePath" Return="ignore" Execute="immediate" BinaryRef="WixUIWixca$(var.Suffix)" />
14 - </Fragment>
7 + <!--
8 + Custom actions to print EULA amd validate install directories are defined
9 + in WixUIExtension compiler extension, to handle platform-specific custom
10 + actions referred to from `DoAction` control events.
11 + -->
12
13 <Fragment>
17 - <Binary Id="WixUIWixca$(var.Suffix)" SourceFile="!(bindpath.$(var.platform))uica.dll" />
14 + <Binary Id="WixUiCa$(var.Suffix)" SourceFile="!(bindpath.$(var.platform))uica.dll" />
15 </Fragment>
16 </Include>
src/ext/UI/wixlib/Common_arm64.wxs new
+7
@@ -0,0 +1,7 @@
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 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 + <?define platform=arm64 ?>
6 + <?include Common_Platform.wxi ?>
7 +</Wix>
src/ext/UI/wixlib/Common_x64.wxs new
+7
@@ -0,0 +1,7 @@
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 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 + <?define platform=x64 ?>
6 + <?include Common_Platform.wxi ?>
7 +</Wix>
src/ext/UI/wixlib/WixUI_Advanced.wxs
-1
@@ -53,7 +53,6 @@ Todo:
53 <TextStyle Id="WixUI_Font_Emphasized" FaceName="!(loc.Advanced_Font_FaceName)" Size="!(loc.Advanced_Font_Emphasized_Size)" Bold="yes" />
54
55 <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
56 - <Property Id="WixUI_Mode" Value="Advanced" />
56
57 <DialogRef Id="BrowseDlg" />
58 <DialogRef Id="DiskCostDlg" />
src/ext/UI/wixlib/WixUI_FeatureTree.wxs
-1
@@ -29,7 +29,6 @@ Patch dialog sequence:
29 <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
30
31 <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
32 - <Property Id="WixUI_Mode" Value="FeatureTree" />
32
33 <DialogRef Id="ErrorDlg" />
34 <DialogRef Id="FatalError" />
src/ext/UI/wixlib/WixUI_InstallDir.wxs
-1
@@ -30,7 +30,6 @@ Patch dialog sequence:
30 <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
31
32 <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
33 - <Property Id="WixUI_Mode" Value="InstallDir" />
33
34 <DialogRef Id="BrowseDlg" />
35 <DialogRef Id="DiskCostDlg" />
src/ext/UI/wixlib/WixUI_Minimal.wxs
-1
@@ -24,7 +24,6 @@ Patch dialog sequence:
24 <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
25
26 <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
27 - <Property Id="WixUI_Mode" Value="Minimal" />
27
28 <DialogRef Id="ErrorDlg" />
29 <DialogRef Id="FatalError" />
src/ext/UI/wixlib/WixUI_Mondo.wxs
-1
@@ -31,7 +31,6 @@ Patch dialog sequence:
31 <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
32
33 <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
34 - <Property Id="WixUI_Mode" Value="Mondo" />
34
35 <DialogRef Id="ErrorDlg" />
36 <DialogRef Id="FatalError" />
src/ext/UI/wixlib/caSuffix.wxi deleted
-27
@@ -1,27 +0,0 @@
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 -<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
4 - <?ifndef platform ?>
5 - <?error Required value "platform" not defined in include caSuffix.wxi ?>
6 - <?endif?>
7 -
8 - <?ifdef Suffix ?>
9 - <?undef Suffix ?>
10 - <?undef DeferredSuffix ?>
11 - <?endif?>
12 -
13 - <?if $(var.platform)="x86" ?>
14 - <?define Suffix="" ?>
15 - <?define DeferredSuffix="" ?>
16 - <?endif?>
17 -
18 - <?if $(var.platform)="x64" ?>
19 - <?define Suffix="_x64" ?>
20 - <?define DeferredSuffix="_64" ?>
21 - <?endif?>
22 -
23 - <?if $(var.platform)="arm" ?>
24 - <?define Suffix="_ARM" ?>
25 - <?define DeferredSuffix="_ARM" ?>
26 - <?endif?>
27 -</Include>
src/ext/UI/wixlib/ui.wixproj
+3 -1
@@ -27,7 +27,9 @@
27 </ItemGroup>
28
29 <ItemGroup>
30 - <ProjectReference Include="..\ca\uica.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" />
30 + <ProjectReference Include="..\ca\uica.vcxproj" Properties="Platform=x86" />
31 + <ProjectReference Include="..\ca\uica.vcxproj" Properties="Platform=x64" />
32 + <ProjectReference Include="..\ca\uica.vcxproj" Properties="Platform=ARM64" />
33 </ItemGroup>
34
35 <ItemGroup>
src/test/burn/TestData/FilesInUseTests/PackageA/PackageA.wxs
+2 -2
@@ -1,10 +1,10 @@
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 -<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
4 <Fragment>
5 <ComponentGroup Id="ProductComponents" />
6
7 - <UIRef Id="WixUI_Minimal" />
7 + <ui:WixUI Id="WixUI_Minimal" />
8 <WixVariable Id="WixUILicenseRtf" Value="license.txt" />
9 </Fragment>
10 </Wix>
src/test/wix/TestData/WixprojLibraryVcxprojDll/Library.wxs
+1 -3
@@ -1,11 +1,9 @@
1 -<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
2 <Fragment>
3 <ComponentGroup Id='VcxprojDllComponentGroup' Directory='ApplicationFolder'>
4 <Component>
5 <File Source='VcxprojDll.dll' />
6 </Component>
7 </ComponentGroup>
8 -
9 - <UIRef Id="WixUI_Minimal" />
8 </Fragment>
9 </Wix>
src/test/wix/TestData/WixprojPackageCsprojWebApplicationNetCore/Package.wxs
-2
@@ -12,7 +12,5 @@
12 <File Source='web.config' />
13 </Component>
14 </Feature>
15 -
16 - <UIRef Id="WixUI_Minimal" />
15 </Package>
16 </Wix>
src/test/wix/TestData/WixprojPackageCsprojWebApplicationNetCore/WixprojPackageCsprojWebApplicationNetCore.wixproj
-1
@@ -11,7 +11,6 @@
11 <ItemGroup>
12 <!-- SkipPublish="true" BindPath="$(MSBuildProjectDirectory)\does\not\exist" BindName="Xxx" Publish="true" -->
13 <ProjectReference Include="..\CsprojWebApplicationNetCore\CsprojWebApplicationNetCore.csproj" Publish="true" />
14 - <PackageReference Include="WixToolset.UI.wixext" Version="4.0.0-preview.0" />
14 </ItemGroup>
15
16 <!-- <Import Sdk="WixToolset.Sdk" Project='D:\src\wix4\build\wix\Debug\netcoreapp3.1\Sdk\Sdk.targets' /> -->
src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs
-2
@@ -16,7 +16,5 @@
16
17 <MergeRef Id='WinFormsModule' />
18 </Feature>
19 -
20 - <UIRef Id="WixUI_Minimal" />
19 </Package>
20 </Wix>
src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/WixprojPackageVcxprojWindowsApp.wixproj
-2
@@ -5,7 +5,5 @@
5 <ProjectReference Include="..\VcxprojWindowsApp\VcxprojWindowsApp.vcxproj" />
6 <ProjectReference Include="..\WixprojLibraryVcxprojDll\WixprojLibraryVcxprojDll.wixproj" />
7 <ProjectReference Include="..\WixprojModuleCsprojWinFormsNetFx\WixprojModuleCsprojWinFormsNetFx.wixproj" />
8 -
9 - <PackageReference Include="WixToolset.UI.wixext" Version="4.0.0-preview.0" />
8 </ItemGroup>
9 </Project>
src/wix/WixToolset.Converters/WixConverter.cs
+27 -9
@@ -57,6 +57,7 @@ namespace WixToolset.Converters
57 private static readonly XNamespace WixBalNamespace = "http://wixtoolset.org/schemas/v4/wxs/bal";
58 private static readonly XNamespace WixDependencyNamespace = "http://wixtoolset.org/schemas/v4/wxs/dependency";
59 private static readonly XNamespace WixFirewallNamespace = "http://wixtoolset.org/schemas/v4/wxs/firewall";
60 + private static readonly XNamespace WixUiNamespace = "http://wixtoolset.org/schemas/v4/wxs/ui";
61 private static readonly XNamespace WixUtilNamespace = "http://wixtoolset.org/schemas/v4/wxs/util";
62 private static readonly XNamespace WixVSNamespace = "http://wixtoolset.org/schemas/v4/wxs/vs";
63
@@ -142,6 +143,7 @@ namespace WixToolset.Converters
143 private static readonly XName UtilXmlConfigElementName = WixUtilNamespace + "XmlConfig";
144 private static readonly XName CustomActionElementName = WixNamespace + "CustomAction";
145 private static readonly XName CustomActionRefElementName = WixNamespace + "CustomActionRef";
146 + private static readonly XName UIRefElementName = WixNamespace + "UIRef";
147 private static readonly XName PropertyElementName = WixNamespace + "Property";
148 private static readonly XName Wix4ElementName = WixNamespace + "Wix";
149 private static readonly XName Wix3ElementName = Wix3Namespace + "Wix";
@@ -259,6 +261,7 @@ namespace WixToolset.Converters
261 { WixConverter.WixElementWithoutNamespaceName, this.ConvertElementWithoutNamespace },
262 { WixConverter.IncludeElementWithoutNamespaceName, this.ConvertElementWithoutNamespace },
263 { WixConverter.VerbElementName, this.ConvertVerbElement },
264 + { WixConverter.UIRefElementName, this.ConvertUIRefElement },
265 };
266
267 this.Messaging = messaging;
@@ -1275,14 +1278,14 @@ namespace WixToolset.Converters
1278 xPackage.SetAttributeValue("Scope", "perUser");
1279 break;
1280 case "elevated":
1281 + {
1282 + var xAllUsers = xPackage.Elements(PropertyElementName).SingleOrDefault(p => p.Attribute("Id")?.Value == "ALLUSERS");
1283 + if (xAllUsers?.Attribute("Value")?.Value == "1")
1284 {
1279 - var xAllUsers = xPackage.Elements(PropertyElementName).SingleOrDefault(p => p.Attribute("Id")?.Value == "ALLUSERS");
1280 - if (xAllUsers?.Attribute("Value")?.Value == "1")
1281 - {
1282 - xAllUsers?.Remove();
1283 - }
1285 + xAllUsers?.Remove();
1286 }
1285 - break;
1287 + }
1288 + break;
1289 }
1290
1291 xInstallPrivileges?.Remove();
@@ -1439,7 +1442,7 @@ namespace WixToolset.Converters
1442 }
1443
1444 if (!String.IsNullOrEmpty(newElementName)
1442 - && this.OnError(ConverterTestType.ReferencesReplaced, element, "Custom action and property reference {0} have been replaced with strongly-typed elements.", id))
1445 + && this.OnError(ConverterTestType.ReferencesReplaced, element, "UI, custom action, and property reference {0} has been replaced with strongly-typed element.", id))
1446 {
1447 this.XRoot.SetAttributeValue(XNamespace.Xmlns + newNamespaceName, newNamespace.NamespaceName);
1448
@@ -1452,6 +1455,21 @@ namespace WixToolset.Converters
1455 }
1456 }
1457
1458 + private void ConvertUIRefElement(XElement element)
1459 + {
1460 + var id = element.Attribute("Id")?.Value;
1461 +
1462 + if (id?.StartsWith("WixUI_") == true
1463 + && this.OnError(ConverterTestType.ReferencesReplaced, element, "UI, custom action, and property reference {0} has been replaced with strongly-typed element.", id))
1464 + {
1465 + this.XRoot.SetAttributeValue(XNamespace.Xmlns + "ui", WixUiNamespace.NamespaceName);
1466 +
1467 + element.AddBeforeSelf(new XElement(WixUiNamespace + "WixUI", new XAttribute("Id", id)));
1468 +
1469 + element.Remove();
1470 + }
1471 + }
1472 +
1473 private void ConvertCustomActionRefElement(XElement element)
1474 {
1475 var newElementName = String.Empty;
@@ -1471,7 +1489,7 @@ namespace WixToolset.Converters
1489 }
1490
1491 if (!String.IsNullOrEmpty(newElementName)
1474 - && this.OnError(ConverterTestType.ReferencesReplaced, element, "Custom action and property reference {0} have been replaced with strongly-typed elements.", id))
1492 + && this.OnError(ConverterTestType.ReferencesReplaced, element, "UI, custom action, and property reference {0} has been replaced with strongly-typed element.", id))
1493 {
1494 element.AddAfterSelf(new XElement(WixUtilNamespace + newElementName));
1495 element.Remove();
@@ -2532,7 +2550,7 @@ namespace WixToolset.Converters
2550 DefiningStandardDirectoryDeprecated,
2551
2552 /// <summary>
2535 - /// Naked custom action and property references replaced with elements.
2553 + /// Naked UI, custom action, and property references replaced with elements.
2554 /// </summary>
2555 ReferencesReplaced,
2556
src/wix/test/WixToolsetTest.Converters/UIExtensionFixture.cs new
+59
@@ -0,0 +1,59 @@
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.Converters
4 +{
5 + using System;
6 + using System.Xml.Linq;
7 + using WixBuildTools.TestSupport;
8 + using WixToolset.Converters;
9 + using WixToolsetTest.Converters.Mocks;
10 + using Xunit;
11 +
12 + public class UIExtensionFixture : BaseConverterFixture
13 + {
14 + [Fact]
15 + public void FixUIRefs()
16 + {
17 + var parse = String.Join(Environment.NewLine,
18 + "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>",
19 + " <Fragment>",
20 + " <UIRef Id=\"WixUI_Advanced\" />",
21 + " <UIRef Id=\"WixUI_FeatureTree\" />",
22 + " <UIRef Id=\"WixUI_BobsSpecialUI\" />",
23 + " <UI>",
24 + " <UIRef Id=\"WixUI_Advanced\" />",
25 + " <UIRef Id=\"WixUI_FeatureTree\" />",
26 + " <UIRef Id=\"WixUI_BobsSpecialUI\" />",
27 + " </UI>",
28 + " </Fragment>",
29 + "</Wix>");
30 +
31 + var expected = new[]
32 + {
33 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\" xmlns:ui=\"http://wixtoolset.org/schemas/v4/wxs/ui\">",
34 + " <Fragment>",
35 + " <ui:WixUI Id=\"WixUI_Advanced\" />",
36 + " <ui:WixUI Id=\"WixUI_FeatureTree\" />",
37 + " <ui:WixUI Id=\"WixUI_BobsSpecialUI\" />",
38 + " <UI>",
39 + " <ui:WixUI Id=\"WixUI_Advanced\" />",
40 + " <ui:WixUI Id=\"WixUI_FeatureTree\" />",
41 + " <ui:WixUI Id=\"WixUI_BobsSpecialUI\" />",
42 + " </UI>",
43 + " </Fragment>",
44 + "</Wix>"
45 + };
46 +
47 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
48 +
49 + var messaging = new MockMessaging();
50 + var converter = new WixConverter(messaging, 2, null, null);
51 +
52 + var errors = converter.ConvertDocument(document);
53 + Assert.Equal(7, errors);
54 +
55 + var actualLines = UnformattedDocumentLines(document);
56 + WixAssert.CompareLineByLine(expected, actualLines);
57 + }
58 + }
59 +}