@joebigelow / wix-1 / commits / 913b6238

Add WixInternalUIBootstrapperApplication as a new built-in BA.

Implements 6835

Sean Hall committed Jul 19, 2022 at 15:17 UTC 913b6238417dceeb8440315e4669990756d17655
92 files changed +3352 -151
src/api/burn/WixToolset.Mba.Core/IPackageInfo.cs
+5
@@ -67,6 +67,11 @@ namespace WixToolset.Mba.Core
67 /// </summary>
68 string PrereqLicenseUrl { get; }
69
70 + /// <summary>
71 + /// See <see cref="PrimaryPackageType"/>
72 + /// </summary>
73 + PrimaryPackageType PrimaryPackageType { get; }
74 +
75 /// <summary>
76 ///
77 /// </summary>
src/api/burn/WixToolset.Mba.Core/PackageInfo.cs
+34
@@ -63,6 +63,37 @@ namespace WixToolset.Mba.Core
63 ChainBundle,
64 }
65
66 + /// <summary>
67 + /// Metadata for BAs like WixInternalUIBootstrapperApplication that only support one main package.
68 + /// </summary>
69 + public enum PrimaryPackageType
70 + {
71 + /// <summary>
72 + /// Not a primary package.
73 + /// </summary>
74 + None,
75 +
76 + /// <summary>
77 + /// The default package if no architecture specific package is available for the current architecture.
78 + /// </summary>
79 + Default,
80 +
81 + /// <summary>
82 + /// The package to use on x86 machines.
83 + /// </summary>
84 + X86,
85 +
86 + /// <summary>
87 + /// The package to use on x64 machines.
88 + /// </summary>
89 + X64,
90 +
91 + /// <summary>
92 + /// The package to use on ARM64 machines.
93 + /// </summary>
94 + ARM64,
95 + }
96 +
97 /// <summary>
98 /// Default implementation of <see cref="IPackageInfo"/>.
99 /// </summary>
@@ -116,6 +147,9 @@ namespace WixToolset.Mba.Core
147 /// <inheritdoc/>
148 public string PrereqLicenseUrl { get; internal set; }
149
150 + /// <inheritdoc/>
151 + public PrimaryPackageType PrimaryPackageType { get; internal set; }
152 +
153 /// <inheritdoc/>
154 public object CustomData { get; set; }
155
src/api/burn/balutil/balinfo.cpp
+27
@@ -529,6 +529,33 @@ static HRESULT ParseBalPackageInfoFromXml(
529 hr = XmlGetAttributeEx(pNode, L"DisplayInternalUICondition", &pPackage->sczDisplayInternalUICondition);
530 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get DisplayInternalUICondition setting for package.");
531
532 + hr = XmlGetAttributeEx(pNode, L"PrimaryPackageType", &scz);
533 + ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get PrimaryPackageType setting for package.");
534 +
535 + if (fXmlFound)
536 + {
537 + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"default", -1))
538 + {
539 + pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT;
540 + }
541 + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"x86", -1))
542 + {
543 + pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X86;
544 + }
545 + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"x64", -1))
546 + {
547 + pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X64;
548 + }
549 + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"arm64", -1))
550 + {
551 + pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_ARM64;
552 + }
553 + else
554 + {
555 + ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for WixBalPackageInfo/@PrimaryPackageType: %ls", scz);
556 + }
557 + }
558 +
559 ReleaseNullObject(pNode);
560 }
561 ExitOnFailure(hr, "Failed to parse all WixBalPackageInfo elements.");
src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h
+11 -3
@@ -451,8 +451,8 @@ public: // IBootstrapperApplication
451 __in BOOTSTRAPPER_ERROR_TYPE errorType,
452 __in_z LPCWSTR wzPackageId,
453 __in DWORD dwCode,
454 - __in_z LPCWSTR /*wzError*/,
455 - __in DWORD /*dwUIHint*/,
454 + __in_z LPCWSTR wzError,
455 + __in DWORD dwUIHint,
456 __in DWORD /*cData*/,
457 __in_ecount_z_opt(cData) LPCWSTR* /*rgwzData*/,
458 __in int /*nRecommendation*/,
@@ -461,7 +461,15 @@ public: // IBootstrapperApplication
461 {
462 BalRetryErrorOccurred(wzPackageId, dwCode);
463
464 - if (CheckCanceled())
464 + if (BOOTSTRAPPER_DISPLAY_EMBEDDED == m_display)
465 + {
466 + HRESULT hr = m_pEngine->SendEmbeddedError(dwCode, wzError, dwUIHint, pResult);
467 + if (FAILED(hr))
468 + {
469 + *pResult = IDERROR;
470 + }
471 + }
472 + else if (CheckCanceled())
473 {
474 *pResult = IDCANCEL;
475 }
src/api/burn/balutil/inc/balinfo.h
+10
@@ -20,6 +20,15 @@ typedef enum BAL_INFO_PACKAGE_TYPE
20 BAL_INFO_PACKAGE_TYPE_BUNDLE_CHAIN,
21 } BAL_INFO_PACKAGE_TYPE;
22
23 +typedef enum _BAL_INFO_PRIMARY_PACKAGE_TYPE
24 +{
25 + BAL_INFO_PRIMARY_PACKAGE_TYPE_NONE,
26 + BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT,
27 + BAL_INFO_PRIMARY_PACKAGE_TYPE_X86,
28 + BAL_INFO_PRIMARY_PACKAGE_TYPE_X64,
29 + BAL_INFO_PRIMARY_PACKAGE_TYPE_ARM64,
30 +} BAL_INFO_PRIMARY_PACKAGE_TYPE;
31 +
32 typedef enum _BAL_INFO_RESTART
33 {
34 BAL_INFO_RESTART_UNKNOWN,
@@ -54,6 +63,7 @@ typedef struct _BAL_INFO_PACKAGE
63 BOOL fPrereqPackage;
64 LPWSTR sczPrereqLicenseFile;
65 LPWSTR sczPrereqLicenseUrl;
66 + BAL_INFO_PRIMARY_PACKAGE_TYPE primaryPackageType;
67 LPVOID pvCustomData;
68 } BAL_INFO_PACKAGE;
69
src/api/wix/WixToolset.Data/Burn/BurnConstants.cs
+3
@@ -14,6 +14,9 @@ namespace WixToolset.Data.Burn
14 public const string BundleExtensionDataWixOutputStreamName = "wix-bextdata";
15 public const string BootstrapperApplicationDataWixOutputStreamName = "wix-badata.xml";
16
17 + public const string BootstrapperApplicationDataNamespace = "http://wixtoolset.org/schemas/v4/BootstrapperApplicationData";
18 + public const string BundleExtensionDataNamespace = "http://wixtoolset.org/schemas/v4/BundleExtensionData";
19 +
20 public const string BootstrapperApplicationDataSymbolDefinitionTag = "WixBootstrapperApplicationData";
21 public const string BundleExtensionSearchSymbolDefinitionTag = "WixBundleExtensionSearch";
22
src/burn/engine/core.cpp
+3 -3
@@ -447,9 +447,6 @@ extern "C" HRESULT CorePlan(
447 BURN_PACKAGE* pForwardCompatibleBundlePackage = NULL;
448 BOOL fContinuePlanning = TRUE; // assume we won't skip planning due to dependencies.
449
450 - hr = PlanSetVariables(action, &pEngineState->variables);
451 - ExitOnFailure(hr, "Failed to update action.");
452 -
450 LogId(REPORT_STANDARD, MSG_PLAN_BEGIN, pEngineState->packages.cPackages, LoggingBurnActionToString(action));
451
452 fPlanBegan = TRUE;
@@ -469,6 +466,9 @@ extern "C" HRESULT CorePlan(
466 pEngineState->fPlanned = FALSE;
467 PlanReset(&pEngineState->plan, &pEngineState->variables, &pEngineState->containers, &pEngineState->packages, &pEngineState->layoutPayloads);
468
469 + hr = PlanSetVariables(action, &pEngineState->variables);
470 + ExitOnFailure(hr, "Failed to update action.");
471 +
472 // Remember the overall action state in the plan since it shapes the changes
473 // we make everywhere.
474 pEngineState->plan.action = action;
src/burn/engine/splashscreen.cpp
+1 -1
@@ -170,7 +170,7 @@ static DWORD WINAPI ThreadProc(
170 SPLASHSCREEN_INFO splashScreenInfo = { };
171
172 WNDCLASSW wc = { };
173 - BOOL fRegistered = TRUE;
173 + BOOL fRegistered = FALSE;
174
175 BOOL fRet = FALSE;
176 MSG msg = { };
src/burn/engine/uithread.cpp
+1 -1
@@ -98,7 +98,7 @@ static DWORD WINAPI ThreadProc(
98 UITHREAD_INFO info = { };
99
100 WNDCLASSW wc = { };
101 - BOOL fRegistered = TRUE;
101 + BOOL fRegistered = FALSE;
102 HWND hWnd = NULL;
103
104 BOOL fRet = FALSE;
src/ext/Bal/Bal.wixext.sln
+18
@@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bafunctions", "Samples\bafu
9 EndProject
10 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mbahost", "mbahost\mbahost.vcxproj", "{12C87C77-3547-44F8-8134-29BC915CB19D}"
11 EndProject
12 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wixiuiba", "wixiuiba\wixiuiba.vcxproj", "{0F73E566-925C-448D-99CB-3A7F5DF399C8}"
13 +EndProject
14 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wixstdba", "wixstdba\wixstdba.vcxproj", "{41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}"
15 EndProject
16 Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "bal", "wixlib\bal.wixproj", "{3444D952-F21C-496F-AB6B-56435BFD0787}"
@@ -83,6 +85,22 @@ Global
85 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|x64.Build.0 = Release|x64
86 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|x86.ActiveCfg = Release|Win32
87 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|x86.Build.0 = Release|Win32
88 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Debug|Any CPU.ActiveCfg = Debug|Win32
89 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Debug|Any CPU.Build.0 = Debug|Win32
90 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Debug|ARM64.ActiveCfg = Debug|ARM64
91 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Debug|ARM64.Build.0 = Debug|ARM64
92 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Debug|x64.ActiveCfg = Debug|x64
93 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Debug|x64.Build.0 = Debug|x64
94 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Debug|x86.ActiveCfg = Debug|Win32
95 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Debug|x86.Build.0 = Debug|Win32
96 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Release|Any CPU.ActiveCfg = Release|Win32
97 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Release|Any CPU.Build.0 = Release|Win32
98 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Release|ARM64.ActiveCfg = Release|ARM64
99 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Release|ARM64.Build.0 = Release|ARM64
100 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Release|x64.ActiveCfg = Release|x64
101 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Release|x64.Build.0 = Release|x64
102 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Release|x86.ActiveCfg = Release|Win32
103 + {0F73E566-925C-448D-99CB-3A7F5DF399C8}.Release|x86.Build.0 = Release|Win32
104 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|Any CPU.ActiveCfg = Debug|Win32
105 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|Any CPU.Build.0 = Debug|Win32
106 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|ARM64.ActiveCfg = Debug|ARM64
src/ext/Bal/bal.cmd
-8
@@ -14,14 +14,6 @@ nuget restore dnchost\packages.config || exit /b
14 msbuild -t:Restore -p:Configuration=%_C% || exit /b
15
16 :: Build
17 -msbuild -p:Configuration=%_C%;Platform=x86 dnchost\dnchost.vcxproj || exit /b
18 -msbuild -p:Configuration=%_C%;Platform=x64 dnchost\dnchost.vcxproj || exit /b
19 -msbuild -p:Configuration=%_C%;Platform=ARM64 dnchost\dnchost.vcxproj || exit /b
20 -
21 -msbuild -p:Configuration=%_C%;Platform=x86 mbahost\mbahost.vcxproj || exit /b
22 -msbuild -p:Configuration=%_C%;Platform=x64 mbahost\mbahost.vcxproj || exit /b
23 -msbuild -p:Configuration=%_C%;Platform=ARM64 mbahost\mbahost.vcxproj || exit /b
24 -
17 msbuild -p:Configuration=%_C%;Platform=x86 test\examples\TestEngine\Example.TestEngine.vcxproj || exit /b
18 msbuild -p:Configuration=%_C%;Platform=x64 test\examples\TestEngine\Example.TestEngine.vcxproj || exit /b
19 msbuild -p:Configuration=%_C%;Platform=ARM64 test\examples\TestEngine\Example.TestEngine.vcxproj || exit /b
src/ext/Bal/dnchost/dnchost.cpp
+5 -3
@@ -110,18 +110,18 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
110 {
111 if (DNCHOSTTYPE_SCD == vstate.type)
112 {
113 - vstate.prereqData.hrHostInitialization = E_DNCHOST_SCD_RUNTIME_FAILURE;
113 + vstate.prereqData.hrFatalError = E_DNCHOST_SCD_RUNTIME_FAILURE;
114 BalLogError(hr, "The self-contained .NET Core runtime failed to load. This is an unrecoverable error.");
115 }
116 else if (vstate.prereqData.fCompleted)
117 {
118 hr = E_PREREQBA_INFINITE_LOOP;
119 BalLogError(hr, "The prerequisites were already installed. The bootstrapper application will not be reloaded to prevent an infinite loop.");
120 - vstate.prereqData.hrHostInitialization = hr;
120 + vstate.prereqData.hrFatalError = hr;
121 }
122 else
123 {
124 - vstate.prereqData.hrHostInitialization = S_OK;
124 + vstate.prereqData.hrFatalError = S_OK;
125 }
126 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because .NET Core host could not be loaded, error: 0x%08x.", hr);
127
@@ -233,6 +233,8 @@ static HRESULT LoadDncConfiguration(
233 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value.");
234 }
235
236 + pState->prereqData.fPerformHelp = !pState->prereqData.fAlwaysInstallPrereqs;
237 +
238 pState->type = DNCHOSTTYPE_FDD;
239
240 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixDncOptions", &pixnHost);
src/ext/Bal/mbahost/mbahost.cpp
+5 -3
@@ -144,17 +144,17 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
144 if (E_MBAHOST_NET452_ON_WIN7RTM == hr)
145 {
146 BalLogError(hr, "The Burn engine cannot run with an MBA under the .NET 4 CLR on Windows 7 RTM with .NET 4.5.2 (or greater) installed.");
147 - vstate.prereqData.hrHostInitialization = hr;
147 + vstate.prereqData.hrFatalError = hr;
148 }
149 else if (vstate.prereqData.fCompleted)
150 {
151 hr = E_PREREQBA_INFINITE_LOOP;
152 BalLogError(hr, "The prerequisites were already installed. The bootstrapper application will not be reloaded to prevent an infinite loop.");
153 - vstate.prereqData.hrHostInitialization = hr;
153 + vstate.prereqData.hrFatalError = hr;
154 }
155 else
156 {
157 - vstate.prereqData.hrHostInitialization = S_OK;
157 + vstate.prereqData.hrFatalError = S_OK;
158 }
159
160 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because managed host could not be loaded, error: 0x%08x.", hr);
@@ -306,6 +306,8 @@ static HRESULT LoadMbaConfiguration(
306 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value.");
307 }
308
309 + pState->prereqData.fPerformHelp = !pState->prereqData.fAlwaysInstallPrereqs;
310 +
311 LExit:
312 ReleaseObject(pixnHost);
313 ReleaseObject(pixdManifest);
src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
+6
@@ -143,6 +143,12 @@ namespace WixToolsetTest.Bal
143 {
144 "<WixMbaPrereqOptions AlwaysInstallPrereqs='1' />",
145 }, wixMbaPrereqOptionsElements);
146 +
147 + var wixMbaPrereqInformationElements = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixMbaPrereqInformation");
148 + WixAssert.CompareLineByLine(new[]
149 + {
150 + "<WixMbaPrereqInformation PackageId='wixnative.exe' />",
151 + }, wixMbaPrereqInformationElements);
152 }
153 }
154
src/ext/Bal/test/WixToolsetTest.Bal/InternalUIBAFixture.cs new
+474
@@ -0,0 +1,474 @@
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.Bal
4 +{
5 + using System;
6 + using System.IO;
7 + using System.Linq;
8 + using WixBuildTools.TestSupport;
9 + using WixToolset.Core.TestPackage;
10 + using Xunit;
11 +
12 + public class InternalUIBAFixture
13 + {
14 + [Fact]
15 + public void CanBuildUsingWixIuiBa()
16 + {
17 + using (var fs = new DisposableFileSystem())
18 + {
19 + var baseFolder = fs.GetFolder();
20 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
21 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
22 + var intermediateFolder = Path.Combine(baseFolder, "obj");
23 + var baFolderPath = Path.Combine(baseFolder, "ba");
24 + var extractFolderPath = Path.Combine(baseFolder, "extract");
25 +
26 + var compileResult = WixRunner.Execute(new[]
27 + {
28 + "build",
29 + Path.Combine(bundleSourceFolder, "SinglePrimaryPackage.wxs"),
30 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
31 + "-intermediateFolder", intermediateFolder,
32 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
33 + "-o", bundleFile,
34 + });
35 + compileResult.AssertSuccess();
36 +
37 + Assert.True(File.Exists(bundleFile));
38 +
39 + var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath);
40 + extractResult.AssertSuccess();
41 +
42 + var balPackageInfos = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixBalPackageInfo");
43 + WixAssert.CompareLineByLine(new string[]
44 + {
45 + "<WixBalPackageInfo PackageId='test.msi' PrimaryPackageType='default' />",
46 + }, balPackageInfos);
47 +
48 + Assert.True(File.Exists(Path.Combine(baFolderPath, "mbapreq.thm")));
49 + Assert.True(File.Exists(Path.Combine(baFolderPath, "mbapreq.wxl")));
50 + }
51 + }
52 +
53 + [Fact]
54 + public void CanBuildUsingWixIuiBaWithImplicitPrimaryPackage()
55 + {
56 + using (var fs = new DisposableFileSystem())
57 + {
58 + var baseFolder = fs.GetFolder();
59 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
60 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
61 + var intermediateFolder = Path.Combine(baseFolder, "obj");
62 + var baFolderPath = Path.Combine(baseFolder, "ba");
63 + var extractFolderPath = Path.Combine(baseFolder, "extract");
64 +
65 + var compileResult = WixRunner.Execute(new[]
66 + {
67 + "build",
68 + Path.Combine(bundleSourceFolder, "ImplicitPrimaryPackage.wxs"),
69 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
70 + "-intermediateFolder", intermediateFolder,
71 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
72 + "-o", bundleFile,
73 + });
74 + compileResult.AssertSuccess();
75 +
76 + Assert.True(File.Exists(bundleFile));
77 +
78 + var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath);
79 + extractResult.AssertSuccess();
80 +
81 + var balPackageInfos = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixBalPackageInfo");
82 + WixAssert.CompareLineByLine(new string[]
83 + {
84 + "<WixBalPackageInfo PackageId='test.msi' PrimaryPackageType='default' />",
85 + }, balPackageInfos);
86 +
87 + var mbaPrereqInfos = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixMbaPrereqInformation");
88 + WixAssert.CompareLineByLine(new[]
89 + {
90 + "<WixMbaPrereqInformation PackageId='wixnative.exe' />",
91 + }, mbaPrereqInfos);
92 +
93 + Assert.True(File.Exists(Path.Combine(baFolderPath, "mbapreq.thm")));
94 + Assert.True(File.Exists(Path.Combine(baFolderPath, "mbapreq.wxl")));
95 + }
96 + }
97 +
98 + [Fact]
99 + public void CanBuildUsingWixIuiBaWithWarnings()
100 + {
101 + using (var fs = new DisposableFileSystem())
102 + {
103 + var baseFolder = fs.GetFolder();
104 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
105 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
106 + var intermediateFolder = Path.Combine(baseFolder, "obj");
107 + var baFolderPath = Path.Combine(baseFolder, "ba");
108 + var extractFolderPath = Path.Combine(baseFolder, "extract");
109 +
110 + var compileResult = WixRunner.Execute(warningsAsErrors: false, new[]
111 + {
112 + "build",
113 + Path.Combine(bundleSourceFolder, "IuiBaWarnings.wxs"),
114 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
115 + "-intermediateFolder", intermediateFolder,
116 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
117 + "-o", bundleFile,
118 + });
119 +
120 + WixAssert.CompareLineByLine(new[]
121 + {
122 + "WixInternalUIBootstrapperApplication does not support the value of 'force' for Cache on prereq packages. Prereq packages are only cached when they need to be installed.",
123 + "WixInternalUIBootstrapperApplication ignores InstallCondition for the primary package so that the MSI UI is always shown.",
124 + "WixInternalUIBootstrapperApplication ignores DisplayInternalUICondition for the primary package so that the MSI UI is always shown.",
125 + "When using WixInternalUIBootstrapperApplication, all prereq packages should be before the primary package in the chain. The prereq packages are always installed before the primary package.",
126 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
127 +
128 + compileResult.AssertSuccess();
129 +
130 + Assert.True(File.Exists(bundleFile));
131 +
132 + var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath);
133 + extractResult.AssertSuccess();
134 +
135 + var balPackageInfos = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixBalPackageInfo");
136 + WixAssert.CompareLineByLine(new string[]
137 + {
138 + "<WixBalPackageInfo PackageId='test.msi' DisplayInternalUICondition='DISPLAYTEST' PrimaryPackageType='default' />",
139 + }, balPackageInfos);
140 +
141 + var mbaPrereqInfos = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixMbaPrereqInformation");
142 + WixAssert.CompareLineByLine(new[]
143 + {
144 + "<WixMbaPrereqInformation PackageId='wixnative.exe' />",
145 + }, mbaPrereqInfos);
146 +
147 + Assert.True(File.Exists(Path.Combine(baFolderPath, "mbapreq.thm")));
148 + Assert.True(File.Exists(Path.Combine(baFolderPath, "mbapreq.wxl")));
149 + }
150 + }
151 +
152 + [Fact]
153 + public void CannotBuildUsingWixIuiBaWithAllPrereqPackages()
154 + {
155 + using (var fs = new DisposableFileSystem())
156 + {
157 + var baseFolder = fs.GetFolder();
158 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
159 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
160 + var intermediateFolder = Path.Combine(baseFolder, "obj");
161 +
162 + var compileResult = WixRunner.Execute(new[]
163 + {
164 + "build",
165 + Path.Combine(bundleSourceFolder, "AllPrereqPackages.wxs"),
166 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
167 + "-intermediateFolder", intermediateFolder,
168 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
169 + "-o", bundleFile,
170 + });
171 +
172 + WixAssert.CompareLineByLine(new[]
173 + {
174 + "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".",
175 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
176 +
177 + Assert.Equal(6808, compileResult.ExitCode);
178 + }
179 + }
180 +
181 + [Fact]
182 + public void CannotBuildUsingWixIuiBaWithImplicitNonMsiPrimaryPackage()
183 + {
184 + using (var fs = new DisposableFileSystem())
185 + {
186 + var baseFolder = fs.GetFolder();
187 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
188 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
189 + var intermediateFolder = Path.Combine(baseFolder, "obj");
190 +
191 + var compileResult = WixRunner.Execute(new[]
192 + {
193 + "build",
194 + Path.Combine(bundleSourceFolder, "ImplicitNonMsiPrimaryPackage.wxs"),
195 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
196 + "-intermediateFolder", intermediateFolder,
197 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
198 + "-o", bundleFile,
199 + });
200 +
201 + WixAssert.CompareLineByLine(new[]
202 + {
203 + "When using WixInternalUIBootstrapperApplication, packages must either be non-permanent and have the bal:PrimaryPackageType attribute, or be permanent and have the bal:PrereqPackage attribute set to 'yes'.",
204 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
205 +
206 + Assert.Equal(6811, compileResult.ExitCode);
207 + }
208 + }
209 +
210 + [Fact]
211 + public void CannotBuildUsingWixIuiBaWithImplicitPrimaryPackageEnableFeatureSelection()
212 + {
213 + using (var fs = new DisposableFileSystem())
214 + {
215 + var baseFolder = fs.GetFolder();
216 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
217 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
218 + var intermediateFolder = Path.Combine(baseFolder, "obj");
219 +
220 + var compileResult = WixRunner.Execute(new[]
221 + {
222 + "build",
223 + Path.Combine(bundleSourceFolder, "ImplicitPrimaryPackageEnableFeatureSelection.wxs"),
224 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
225 + "-intermediateFolder", intermediateFolder,
226 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
227 + "-o", bundleFile,
228 + });
229 +
230 + WixAssert.CompareLineByLine(new[]
231 + {
232 + "When using WixInternalUIBootstrapperApplication, packages must either be non-permanent and have the bal:PrimaryPackageType attribute, or be permanent and have the bal:PrereqPackage attribute set to 'yes'.",
233 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
234 +
235 + Assert.Equal(6811, compileResult.ExitCode);
236 + }
237 + }
238 +
239 + [Fact]
240 + public void CannotBuildUsingWixIuiBaWithMultipleNonPermanentNonPrimaryPackages()
241 + {
242 + using (var fs = new DisposableFileSystem())
243 + {
244 + var baseFolder = fs.GetFolder();
245 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
246 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
247 + var intermediateFolder = Path.Combine(baseFolder, "obj");
248 +
249 + var compileResult = WixRunner.Execute(new[]
250 + {
251 + "build",
252 + Path.Combine(bundleSourceFolder, "MultipleNonPermanentNonPrimaryPackages.wxs"),
253 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
254 + "-intermediateFolder", intermediateFolder,
255 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
256 + "-o", bundleFile,
257 + });
258 +
259 + WixAssert.CompareLineByLine(new[]
260 + {
261 + "When using WixInternalUIBootstrapperApplication, packages must either be non-permanent and have the bal:PrimaryPackageType attribute, or be permanent and have the bal:PrereqPackage attribute set to 'yes'.",
262 + "When using WixInternalUIBootstrapperApplication, packages must either be non-permanent and have the bal:PrimaryPackageType attribute, or be permanent and have the bal:PrereqPackage attribute set to 'yes'.",
263 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
264 +
265 + Assert.Equal(6811, compileResult.ExitCode);
266 + }
267 + }
268 +
269 + [Fact]
270 + public void CannotBuildUsingWixIuiBaWithMultiplePrimaryPackagesOfSameType()
271 + {
272 + using (var fs = new DisposableFileSystem())
273 + {
274 + var baseFolder = fs.GetFolder();
275 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
276 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
277 + var intermediateFolder = Path.Combine(baseFolder, "obj");
278 +
279 + var compileResult = WixRunner.Execute(new[]
280 + {
281 + "build",
282 + Path.Combine(bundleSourceFolder, "MultipleDefaultPrimaryPackages.wxs"),
283 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
284 + "-intermediateFolder", intermediateFolder,
285 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
286 + "-o", bundleFile,
287 + });
288 +
289 + WixAssert.CompareLineByLine(new[]
290 + {
291 + "There may only be one package in the bundle with PrimaryPackageType of 'default'.",
292 + "The location of the package related to the previous error.",
293 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
294 +
295 + Assert.Equal(6810, compileResult.ExitCode);
296 + }
297 + }
298 +
299 + [Fact]
300 + public void CannotBuildUsingWixIuiBaWithNoDefaultPrimaryPackage()
301 + {
302 + using (var fs = new DisposableFileSystem())
303 + {
304 + var baseFolder = fs.GetFolder();
305 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
306 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
307 + var intermediateFolder = Path.Combine(baseFolder, "obj");
308 +
309 + var compileResult = WixRunner.Execute(new[]
310 + {
311 + "build",
312 + Path.Combine(bundleSourceFolder, "NoDefaultPrimaryPackage.wxs"),
313 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
314 + "-intermediateFolder", intermediateFolder,
315 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
316 + "-o", bundleFile,
317 + });
318 +
319 + WixAssert.CompareLineByLine(new[]
320 + {
321 + "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".",
322 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
323 +
324 + Assert.Equal(6808, compileResult.ExitCode);
325 + }
326 + }
327 +
328 + [Fact]
329 + public void CannotBuildUsingWixIuiBaWithNonMsiPrimaryPackage()
330 + {
331 + using (var fs = new DisposableFileSystem())
332 + {
333 + var baseFolder = fs.GetFolder();
334 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
335 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
336 + var intermediateFolder = Path.Combine(baseFolder, "obj");
337 +
338 + var compileResult = WixRunner.Execute(new[]
339 + {
340 + "build",
341 + Path.Combine(bundleSourceFolder, "NonMsiPrimaryPackage.wxs"),
342 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
343 + "-intermediateFolder", intermediateFolder,
344 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
345 + "-o", bundleFile,
346 + });
347 +
348 + WixAssert.CompareLineByLine(new[]
349 + {
350 + "When using WixInternalUIBootstrapperApplication, each primary package must be an MsiPackage.",
351 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
352 +
353 + Assert.Equal(6814, compileResult.ExitCode);
354 + }
355 + }
356 +
357 + [Fact]
358 + public void CannotBuildUsingWixIuiBaWithNonPermanentPrereqPackage()
359 + {
360 + using (var fs = new DisposableFileSystem())
361 + {
362 + var baseFolder = fs.GetFolder();
363 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
364 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
365 + var intermediateFolder = Path.Combine(baseFolder, "obj");
366 +
367 + var compileResult = WixRunner.Execute(new[]
368 + {
369 + "build",
370 + Path.Combine(bundleSourceFolder, "NonPermanentPrereqPackage.wxs"),
371 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
372 + "-intermediateFolder", intermediateFolder,
373 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
374 + "-o", bundleFile,
375 + });
376 +
377 + WixAssert.CompareLineByLine(new[]
378 + {
379 + "When using WixInternalUIBootstrapperApplication and bal:PrereqPackage is set to 'yes', the package must be permanent.",
380 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
381 +
382 + Assert.Equal(6812, compileResult.ExitCode);
383 + }
384 + }
385 +
386 + [Fact]
387 + public void CannotBuildUsingWixIuiBaWithPermanentPrimaryPackage()
388 + {
389 + using (var fs = new DisposableFileSystem())
390 + {
391 + var baseFolder = fs.GetFolder();
392 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
393 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
394 + var intermediateFolder = Path.Combine(baseFolder, "obj");
395 +
396 + var compileResult = WixRunner.Execute(new[]
397 + {
398 + "build",
399 + Path.Combine(bundleSourceFolder, "PermanentPrimaryPackage.wxs"),
400 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
401 + "-intermediateFolder", intermediateFolder,
402 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
403 + "-o", bundleFile,
404 + });
405 +
406 + WixAssert.CompareLineByLine(new[]
407 + {
408 + "When using WixInternalUIBootstrapperApplication, packages with the bal:PrimaryPackageType attribute must not be permanent.",
409 + "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".",
410 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
411 +
412 + Assert.Equal(6808, compileResult.ExitCode);
413 + }
414 + }
415 +
416 + [Fact]
417 + public void CannotBuildUsingWixIuiBaWithPrimaryPackageEnableFeatureSelection()
418 + {
419 + using (var fs = new DisposableFileSystem())
420 + {
421 + var baseFolder = fs.GetFolder();
422 + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
423 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
424 + var intermediateFolder = Path.Combine(baseFolder, "obj");
425 +
426 + var compileResult = WixRunner.Execute(new[]
427 + {
428 + "build",
429 + Path.Combine(bundleSourceFolder, "PrimaryPackageEnableFeatureSelection.wxs"),
430 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
431 + "-intermediateFolder", intermediateFolder,
432 + "-bindpath", TestData.Get(@"TestData\WixStdBa\Data"),
433 + "-o", bundleFile,
434 + });
435 +
436 + WixAssert.CompareLineByLine(new[]
437 + {
438 + "When using WixInternalUIBootstrapperApplication, primary packages must not have feature selection enabled because it interferes with the user selecting feature through the MSI UI.",
439 + "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".",
440 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
441 +
442 + Assert.Equal(6808, compileResult.ExitCode);
443 + }
444 + }
445 +
446 + [Fact]
447 + public void CannotBuildUsingWixIuiBaWithPrimaryPrereqPackage()
448 + {
449 + using (var fs = new DisposableFileSystem())
450 + {
451 + var baseFolder = fs.GetFolder();
452 + var wixlibFile = Path.Combine(baseFolder, "bin", "test.wixlib");
453 + var bundleSourceFolder = TestData.Get(@"TestData\WixIuiBa");
454 + var intermediateFolder = Path.Combine(baseFolder, "obj");
455 +
456 + var compileResult = WixRunner.Execute(new[]
457 + {
458 + "build",
459 + Path.Combine(bundleSourceFolder, "PrimaryPrereqPackage.wxs"),
460 + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
461 + "-intermediateFolder", intermediateFolder,
462 + "-o", wixlibFile,
463 + });
464 +
465 + WixAssert.CompareLineByLine(new[]
466 + {
467 + "The MsiPackage/@PrereqPackage attribute's value, 'yes', cannot be specified with attribute PrimaryPackageType present.",
468 + }, compileResult.Messages.Select(m => m.ToString()).ToArray());
469 +
470 + Assert.Equal(193, compileResult.ExitCode);
471 + }
472 + }
473 + }
474 +}
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/AllPrereqPackages.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{1CD73801-0B08-4B39-B371-00DA49EF715F}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage bal:PrereqPackage="yes" Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 + <MsiPackage bal:PrereqPackage="yes" Permanent="yes" SourceFile="test.msi" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/ImplicitNonMsiPrimaryPackage.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{1CD73801-0B08-4B39-B371-00DA49EF715F}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <MsiPackage SourceFile="test.msi" Permanent="yes" />
10 + <ExePackage UninstallArguments="" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/ImplicitPrimaryPackage.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{1CD73801-0B08-4B39-B371-00DA49EF715F}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 + <MsiPackage SourceFile="test.msi" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/ImplicitPrimaryPackageEnableFeatureSelection.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{1CD73801-0B08-4B39-B371-00DA49EF715F}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 + <MsiPackage SourceFile="test.msi" EnableFeatureSelection="yes" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/IuibaWarnings.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{1CD73801-0B08-4B39-B371-00DA49EF715F}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <MsiPackage SourceFile="test.msi" InstallCondition="INSTALLTEST" bal:DisplayInternalUICondition="DISPLAYTEST" />
10 + <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" Cache="force" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/MultipleDefaultPrimaryPackages.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{5C7B7C41-B3A9-4FFF-952A-B6D68320B9B4}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <MsiPackage Id="One" SourceFile="test.msi" bal:PrimaryPackageType="default" />
10 + <MsiPackage Id="Two" CacheId="dontdothis" SourceFile="test.msi" bal:PrimaryPackageType="default" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/MultipleNonPermanentNonPrimaryPackages.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{1CD73801-0B08-4B39-B371-00DA49EF715F}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage UninstallArguments="" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 + <MsiPackage SourceFile="test.msi" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/NoDefaultPrimaryPackage.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{1CD73801-0B08-4B39-B371-00DA49EF715F}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 + <MsiPackage bal:PrimaryPackageType="x86" SourceFile="test.msi" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/NonMsiPrimaryPackage.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{1CD73801-0B08-4B39-B371-00DA49EF715F}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage UninstallArguments="" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" bal:PrimaryPackageType="x86" />
10 + <MsiPackage SourceFile="test.msi" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/NonPermanentPrereqPackage.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{5C7B7C41-B3A9-4FFF-952A-B6D68320B9B4}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage UninstallArguments="" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" bal:PrereqPackage="yes" />
10 + <MsiPackage SourceFile="test.msi" bal:PrimaryPackageType="default" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/PermanentPrimaryPackage.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{5C7B7C41-B3A9-4FFF-952A-B6D68320B9B4}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" bal:PrereqPackage="yes" />
10 + <MsiPackage SourceFile="test.msi" bal:PrimaryPackageType="default" Permanent="yes" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/PrimaryPackageEnableFeatureSelection.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{5C7B7C41-B3A9-4FFF-952A-B6D68320B9B4}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" bal:PrereqPackage="yes" />
10 + <MsiPackage SourceFile="test.msi" bal:PrimaryPackageType="default" EnableFeatureSelection="yes" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/PrimaryPrereqPackage.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{5C7B7C41-B3A9-4FFF-952A-B6D68320B9B4}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" bal:PrereqPackage="yes" />
10 + <MsiPackage SourceFile="test.msi" bal:PrimaryPackageType="default" bal:PrereqPackage="yes" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixIuiBa/SinglePrimaryPackage.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Bundle Name="WixIuiBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{5C7B7C41-B3A9-4FFF-952A-B6D68320B9B4}">
5 + <BootstrapperApplication>
6 + <bal:WixInternalUIBootstrapperApplication />
7 + </BootstrapperApplication>
8 + <Chain>
9 + <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" bal:PrereqPackage="yes" />
10 + <MsiPackage SourceFile="test.msi" bal:PrimaryPackageType="default" />
11 + </Chain>
12 + </Bundle>
13 +</Wix>
src/ext/Bal/wixext/BalBurnBackendExtension.cs
+284 -10
@@ -5,6 +5,8 @@ namespace WixToolset.Bal
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 + using System.Text;
9 + using System.Xml;
10 using WixToolset.Bal.Symbols;
11 using WixToolset.Data;
12 using WixToolset.Data.Burn;
@@ -29,12 +31,48 @@ namespace WixToolset.Bal
31
32 protected override IReadOnlyCollection<IntermediateSymbolDefinition> SymbolDefinitions => BurnSymbolDefinitions;
33
34 + public override bool TryProcessSymbol(IntermediateSection section, IntermediateSymbol symbol)
35 + {
36 + if (symbol is WixBalPackageInfoSymbol balPackageInfoSymbol)
37 + {
38 + // There might be a more efficient way to do this,
39 + // but this is an easy way to ensure we're creating valid XML.
40 + var sb = new StringBuilder();
41 + using (var writer = XmlWriter.Create(sb))
42 + {
43 + writer.WriteStartElement(symbol.Definition.Name, BurnConstants.BootstrapperApplicationDataNamespace);
44 +
45 + writer.WriteAttributeString("PackageId", balPackageInfoSymbol.PackageId);
46 +
47 + if (balPackageInfoSymbol.DisplayInternalUICondition != null)
48 + {
49 + writer.WriteAttributeString("DisplayInternalUICondition", balPackageInfoSymbol.DisplayInternalUICondition);
50 + }
51 +
52 + if (balPackageInfoSymbol.PrimaryPackageType != BalPrimaryPackageType.None)
53 + {
54 + writer.WriteAttributeString("PrimaryPackageType", balPackageInfoSymbol.PrimaryPackageType.ToString().ToLower());
55 + }
56 +
57 + writer.WriteEndElement();
58 + }
59 +
60 + this.BackendHelper.AddBootstrapperApplicationData(sb.ToString());
61 +
62 + return true;
63 + }
64 + else
65 + {
66 + return base.TryProcessSymbol(section, symbol);
67 + }
68 + }
69 +
70 public override void SymbolsFinalized(IntermediateSection section)
71 {
72 base.SymbolsFinalized(section);
73
74 this.VerifyBalConditions(section);
37 - this.VerifyBalPackageInfos(section);
75 + this.VerifyDisplayInternalUICondition(section);
76 this.VerifyOverridableVariables(section);
77
78 var baSymbol = section.Symbols.OfType<WixBootstrapperApplicationDllSymbol>().SingleOrDefault();
@@ -44,24 +82,31 @@ namespace WixToolset.Bal
82 return;
83 }
84
85 + var isIuiBA = baId.StartsWith("WixInternalUIBootstrapperApplication");
86 var isStdBA = baId.StartsWith("WixStandardBootstrapperApplication");
87 var isMBA = baId.StartsWith("WixManagedBootstrapperApplicationHost");
88 var isDNC = baId.StartsWith("WixDotNetCoreBootstrapperApplicationHost");
89 var isSCD = isDNC && this.VerifySCD(section);
90
91 + if (isIuiBA)
92 + {
93 + // This needs to happen before VerifyPrereqPackages because it can add prereq packages.
94 + this.VerifyPrimaryPackages(section);
95 + }
96 +
97 if (isDNC)
98 {
99 this.FinalizeBAFactorySymbol(section);
100 }
101
57 - if (isStdBA || isMBA || isDNC)
102 + if (isIuiBA || isStdBA || isMBA || isDNC)
103 {
104 this.VerifyBAFunctions(section);
105 }
106
62 - if (isMBA || (isDNC && !isSCD))
107 + if (isIuiBA || isMBA || (isDNC && !isSCD))
108 {
64 - this.VerifyPrereqPackages(section, isDNC);
109 + this.VerifyPrereqPackages(section, isDNC, isIuiBA);
110 }
111 }
112
@@ -133,12 +178,241 @@ namespace WixToolset.Bal
178 }
179 }
180
136 - private void VerifyBalPackageInfos(IntermediateSection section)
181 + private void VerifyDisplayInternalUICondition(IntermediateSection section)
182 + {
183 + foreach (var balPackageInfoSymbol in section.Symbols.OfType<WixBalPackageInfoSymbol>().ToList())
184 + {
185 + if (balPackageInfoSymbol.DisplayInternalUICondition != null)
186 + {
187 + this.BackendHelper.ValidateBundleCondition(balPackageInfoSymbol.SourceLineNumbers, "*Package", "bal:DisplayInternalUICondition", balPackageInfoSymbol.DisplayInternalUICondition, BundleConditionPhase.Plan);
188 + }
189 + }
190 + }
191 +
192 + private void VerifyPrimaryPackages(IntermediateSection section)
193 + {
194 + WixBalPackageInfoSymbol defaultPrimaryPackage = null;
195 + WixBalPackageInfoSymbol x86PrimaryPackage = null;
196 + WixBalPackageInfoSymbol x64PrimaryPackage = null;
197 + WixBalPackageInfoSymbol arm64PrimaryPackage = null;
198 + var nonPermanentNonPrimaryPackages = new List<WixBundlePackageSymbol>();
199 +
200 + var balPackageInfoSymbolsByPackageId = section.Symbols.OfType<WixBalPackageInfoSymbol>().ToDictionary(x => x.PackageId);
201 + var mbaPrereqInfoSymbolsByPackageId = section.Symbols.OfType<WixMbaPrereqInformationSymbol>().ToDictionary(x => x.PackageId);
202 + var msiPackageSymbolsByPackageId = section.Symbols.OfType<WixBundleMsiPackageSymbol>().ToDictionary(x => x.Id.Id);
203 + var packageSymbols = section.Symbols.OfType<WixBundlePackageSymbol>().ToList();
204 + foreach (var packageSymbol in packageSymbols)
205 + {
206 + var packageId = packageSymbol.Id?.Id;
207 + var isPrereq = false;
208 + var primaryPackageType = BalPrimaryPackageType.None;
209 +
210 + if (mbaPrereqInfoSymbolsByPackageId.TryGetValue(packageId, out var _))
211 + {
212 + isPrereq = true;
213 + }
214 +
215 + if (balPackageInfoSymbolsByPackageId.TryGetValue(packageId, out var balPackageInfoSymbol))
216 + {
217 + primaryPackageType = balPackageInfoSymbol.PrimaryPackageType;
218 + }
219 +
220 + if (packageSymbol.Permanent)
221 + {
222 + if (primaryPackageType != BalPrimaryPackageType.None)
223 + {
224 + this.Messaging.Write(BalErrors.IuibaPermanentPrimaryPackageType(packageSymbol.SourceLineNumbers));
225 + }
226 + else
227 + {
228 + if (!isPrereq)
229 + {
230 + var prereqInfoSymbol = section.AddSymbol(new WixMbaPrereqInformationSymbol(packageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Global, packageId))
231 + {
232 + PackageId = packageId,
233 + });
234 +
235 + mbaPrereqInfoSymbolsByPackageId.Add(packageId, prereqInfoSymbol);
236 + }
237 +
238 + this.VerifyIuibaPrereqPackage(packageSymbol);
239 + }
240 + }
241 + else
242 + {
243 + if (isPrereq)
244 + {
245 + if (primaryPackageType == BalPrimaryPackageType.None)
246 + {
247 + this.Messaging.Write(BalErrors.IuibaNonPermanentPrereqPackage(packageSymbol.SourceLineNumbers));
248 + }
249 + else
250 + {
251 + this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(
252 + packageSymbol.SourceLineNumbers,
253 + packageSymbol.Type + "Package",
254 + "PrereqPackage",
255 + "yes",
256 + "PrimaryPackageType"));
257 + }
258 + }
259 + else if (primaryPackageType == BalPrimaryPackageType.None)
260 + {
261 + nonPermanentNonPrimaryPackages.Add(packageSymbol);
262 + }
263 + else if (packageSymbol.Type != WixBundlePackageType.Msi)
264 + {
265 + this.Messaging.Write(BalErrors.IuibaNonMsiPrimaryPackage(packageSymbol.SourceLineNumbers));
266 + }
267 + else if (!msiPackageSymbolsByPackageId.TryGetValue(packageId, out var msiPackageSymbol))
268 + {
269 + throw new WixException($"Missing WixBundleMsiPackageSymbol for package '{packageId}'");
270 + }
271 + else if (msiPackageSymbol.EnableFeatureSelection)
272 + {
273 + this.Messaging.Write(BalErrors.IuibaPrimaryPackageEnableFeatureSelection(packageSymbol.SourceLineNumbers));
274 + }
275 + else
276 + {
277 + if (primaryPackageType == BalPrimaryPackageType.Default)
278 + {
279 + if (defaultPrimaryPackage == null)
280 + {
281 + defaultPrimaryPackage = balPackageInfoSymbol;
282 + }
283 + else
284 + {
285 + this.Messaging.Write(BalErrors.MultiplePrimaryPackageType(balPackageInfoSymbol.SourceLineNumbers, "default"));
286 + this.Messaging.Write(BalErrors.MultiplePrimaryPackageType2(defaultPrimaryPackage.SourceLineNumbers));
287 + }
288 + }
289 + else if (balPackageInfoSymbol.PrimaryPackageType == BalPrimaryPackageType.X86)
290 + {
291 + if (x86PrimaryPackage == null)
292 + {
293 + x86PrimaryPackage = balPackageInfoSymbol;
294 + }
295 + else
296 + {
297 + this.Messaging.Write(BalErrors.MultiplePrimaryPackageType(balPackageInfoSymbol.SourceLineNumbers, "x86"));
298 + this.Messaging.Write(BalErrors.MultiplePrimaryPackageType2(x86PrimaryPackage.SourceLineNumbers));
299 + }
300 + }
301 + else if (balPackageInfoSymbol.PrimaryPackageType == BalPrimaryPackageType.X64)
302 + {
303 + if (x64PrimaryPackage == null)
304 + {
305 + x64PrimaryPackage = balPackageInfoSymbol;
306 + }
307 + else
308 + {
309 + this.Messaging.Write(BalErrors.MultiplePrimaryPackageType(balPackageInfoSymbol.SourceLineNumbers, "x64"));
310 + this.Messaging.Write(BalErrors.MultiplePrimaryPackageType2(x64PrimaryPackage.SourceLineNumbers));
311 + }
312 + }
313 + else if (balPackageInfoSymbol.PrimaryPackageType == BalPrimaryPackageType.ARM64)
314 + {
315 + if (arm64PrimaryPackage == null)
316 + {
317 + arm64PrimaryPackage = balPackageInfoSymbol;
318 + }
319 + else
320 + {
321 + this.Messaging.Write(BalErrors.MultiplePrimaryPackageType(balPackageInfoSymbol.SourceLineNumbers, "arm64"));
322 + this.Messaging.Write(BalErrors.MultiplePrimaryPackageType2(arm64PrimaryPackage.SourceLineNumbers));
323 + }
324 + }
325 + else
326 + {
327 + throw new NotImplementedException();
328 + }
329 +
330 + this.VerifyIuibaPrimaryPackage(packageSymbol, balPackageInfoSymbol);
331 + }
332 + }
333 + }
334 +
335 + if (defaultPrimaryPackage == null && nonPermanentNonPrimaryPackages.Count == 1)
336 + {
337 + var packageSymbol = nonPermanentNonPrimaryPackages[0];
338 +
339 + if (packageSymbol.Type == WixBundlePackageType.Msi)
340 + {
341 + var packageId = packageSymbol.Id?.Id;
342 + var msiPackageSymbol = section.Symbols.OfType<WixBundleMsiPackageSymbol>()
343 + .SingleOrDefault(x => x.Id.Id == packageId);
344 + if (!msiPackageSymbol.EnableFeatureSelection)
345 + {
346 + if (!balPackageInfoSymbolsByPackageId.TryGetValue(packageId, out var balPackageInfoSymbol))
347 + {
348 + balPackageInfoSymbol = section.AddSymbol(new WixBalPackageInfoSymbol(packageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Global, packageId))
349 + {
350 + PackageId = packageId,
351 + });
352 +
353 + balPackageInfoSymbolsByPackageId.Add(packageId, balPackageInfoSymbol);
354 + }
355 +
356 + balPackageInfoSymbol.PrimaryPackageType = BalPrimaryPackageType.Default;
357 + defaultPrimaryPackage = balPackageInfoSymbol;
358 + nonPermanentNonPrimaryPackages.RemoveAt(0);
359 +
360 + this.VerifyIuibaPrimaryPackage(packageSymbol, balPackageInfoSymbol);
361 + }
362 + }
363 + }
364 +
365 + if (nonPermanentNonPrimaryPackages.Count > 0)
366 + {
367 + foreach (var packageSymbol in nonPermanentNonPrimaryPackages)
368 + {
369 + this.Messaging.Write(BalErrors.IuibaNonPermanentNonPrimaryPackage(packageSymbol.SourceLineNumbers));
370 + }
371 + }
372 + else if (defaultPrimaryPackage == null)
373 + {
374 + this.Messaging.Write(BalErrors.MissingIUIPrimaryPackage());
375 + }
376 + else
377 + {
378 + var foundPrimaryPackage = false;
379 + var chainPackageGroupSymbols = section.Symbols.OfType<WixGroupSymbol>()
380 + .Where(x => x.ChildType == ComplexReferenceChildType.Package &&
381 + x.ParentType == ComplexReferenceParentType.PackageGroup &&
382 + x.ParentId == BurnConstants.BundleChainPackageGroupId);
383 + foreach (var chainPackageGroupSymbol in chainPackageGroupSymbols)
384 + {
385 + var packageId = chainPackageGroupSymbol.ChildId;
386 + if (balPackageInfoSymbolsByPackageId.TryGetValue(packageId, out var balPackageInfo) && balPackageInfo.PrimaryPackageType != BalPrimaryPackageType.None)
387 + {
388 + foundPrimaryPackage = true;
389 + }
390 + else if (foundPrimaryPackage && mbaPrereqInfoSymbolsByPackageId.TryGetValue(packageId, out var mbaPrereqInformationSymbol))
391 + {
392 + this.Messaging.Write(BalWarnings.IuibaPrereqPackageAfterPrimaryPackage(chainPackageGroupSymbol.SourceLineNumbers));
393 + }
394 + }
395 + }
396 + }
397 +
398 + private void VerifyIuibaPrereqPackage(WixBundlePackageSymbol packageSymbol)
399 + {
400 + if (packageSymbol.Cache == BundleCacheType.Force)
401 + {
402 + this.Messaging.Write(BalWarnings.IuibaForceCachePrereq(packageSymbol.SourceLineNumbers));
403 + }
404 + }
405 +
406 + private void VerifyIuibaPrimaryPackage(WixBundlePackageSymbol packageSymbol, WixBalPackageInfoSymbol balPackageInfoSymbol)
407 {
138 - var balPackageInfoSymbols = section.Symbols.OfType<WixBalPackageInfoSymbol>().ToList();
139 - foreach (var balPackageInfoSymbol in balPackageInfoSymbols)
408 + if (packageSymbol.InstallCondition != null)
409 + {
410 + this.Messaging.Write(BalWarnings.IuibaPrimaryPackageInstallCondition(packageSymbol.SourceLineNumbers));
411 + }
412 +
413 + if (balPackageInfoSymbol.DisplayInternalUICondition != null)
414 {
141 - this.BackendHelper.ValidateBundleCondition(balPackageInfoSymbol.SourceLineNumbers, "*Package", "bal:DisplayInternalUICondition", balPackageInfoSymbol.DisplayInternalUICondition, BundleConditionPhase.Plan);
415 + this.Messaging.Write(BalWarnings.IuibaPrimaryPackageDisplayInternalUICondition(packageSymbol.SourceLineNumbers));
416 }
417 }
418
@@ -161,10 +435,10 @@ namespace WixToolset.Bal
435 }
436 }
437
164 - private void VerifyPrereqPackages(IntermediateSection section, bool isDNC)
438 + private void VerifyPrereqPackages(IntermediateSection section, bool isDNC, bool isIuiBA)
439 {
440 var prereqInfoSymbols = section.Symbols.OfType<WixMbaPrereqInformationSymbol>().ToList();
167 - if (prereqInfoSymbols.Count == 0)
441 + if (!isIuiBA && prereqInfoSymbols.Count == 0)
442 {
443 var message = isDNC ? BalErrors.MissingDNCPrereq() : BalErrors.MissingMBAPrereq();
444 this.Messaging.Write(message);
src/ext/Bal/wixext/BalCompiler.cs
+200 -69
@@ -16,7 +16,8 @@ namespace WixToolset.Bal
16 /// </summary>
17 public sealed class BalCompiler : BaseCompilerExtension
18 {
19 - private readonly Dictionary<string, WixMbaPrereqInformationSymbol> prereqInfoSymbolsByPackageId;
19 + private readonly Dictionary<string, WixBalPackageInfoSymbol> packageInfoSymbolsByPackageId = new Dictionary<string, WixBalPackageInfoSymbol>();
20 + private readonly Dictionary<string, WixMbaPrereqInformationSymbol> prereqInfoSymbolsByPackageId = new Dictionary<string, WixMbaPrereqInformationSymbol>();
21
22 private enum WixDotNetCoreBootstrapperApplicationHostTheme
23 {
@@ -32,6 +33,13 @@ namespace WixToolset.Bal
33 Standard,
34 }
35
36 + private enum WixInternalUIBootstrapperApplicationTheme
37 + {
38 + Unknown,
39 + None,
40 + Standard,
41 + }
42 +
43 private enum WixStandardBootstrapperApplicationTheme
44 {
45 Unknown,
@@ -43,14 +51,6 @@ namespace WixToolset.Bal
51 RtfLicense,
52 }
53
46 - /// <summary>
47 - /// Instantiate a new BalCompiler.
48 - /// </summary>
49 - public BalCompiler()
50 - {
51 - this.prereqInfoSymbolsByPackageId = new Dictionary<string, WixMbaPrereqInformationSymbol>();
52 - }
53 -
54 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/bal";
55
56 /// <summary>
@@ -83,6 +83,9 @@ namespace WixToolset.Bal
83 case "BootstrapperApplication":
84 switch (element.Name.LocalName)
85 {
86 + case "WixInternalUIBootstrapperApplication":
87 + this.ParseWixInternalUIBootstrapperApplicationElement(intermediate, section, element);
88 + break;
89 case "WixStandardBootstrapperApplication":
90 this.ParseWixStandardBootstrapperApplicationElement(intermediate, section, element);
91 break;
@@ -113,7 +116,6 @@ namespace WixToolset.Bal
116 public override void ParseAttribute(Intermediate intermediate, IntermediateSection section, XElement parentElement, XAttribute attribute, IDictionary<string, string> context)
117 {
118 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(parentElement);
116 - WixMbaPrereqInformationSymbol prereqInfo;
119
120 switch (parentElement.Name.LocalName)
121 {
@@ -137,42 +139,63 @@ namespace WixToolset.Bal
139 case "MsiPackage":
140 case "MspPackage":
141 var displayInternalUICondition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute);
140 - section.AddSymbol(new WixBalPackageInfoSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, packageId))
141 - {
142 - PackageId = packageId,
143 - DisplayInternalUICondition = displayInternalUICondition,
144 - });
142 + var packageInfo = this.GetBalPackageInfoSymbol(section, sourceLineNumbers, packageId);
143 + packageInfo.DisplayInternalUICondition = displayInternalUICondition;
144 break;
145 default:
146 this.ParseHelper.UnexpectedAttribute(parentElement, attribute);
147 break;
148 }
149 break;
151 - case "PrereqLicenseFile":
152 -
153 - if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out prereqInfo))
150 + case "PrimaryPackageType":
151 + {
152 + var primaryPackageType = BalPrimaryPackageType.None;
153 + var primaryPackageTypeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute);
154 + switch (primaryPackageTypeValue)
155 {
155 - // at the time the extension attribute is parsed, the compiler might not yet have
156 - // parsed the PrereqPackage attribute, so we need to get it directly from the parent element.
157 - var prereqPackage = parentElement.Attribute(this.Namespace + "PrereqPackage");
158 -
159 - if (null != prereqPackage && YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, prereqPackage))
160 - {
161 - prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
162 - {
163 - PackageId = packageId,
164 - });
165 -
166 - this.prereqInfoSymbolsByPackageId.Add(packageId, prereqInfo);
167 - }
168 - else
169 - {
170 - this.Messaging.Write(BalErrors.AttributeRequiresPrereqPackage(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseFile"));
156 + case "default":
157 + primaryPackageType = BalPrimaryPackageType.Default;
158 + break;
159 + case "x86":
160 + primaryPackageType = BalPrimaryPackageType.X86;
161 + break;
162 + case "x64":
163 + primaryPackageType = BalPrimaryPackageType.X64;
164 + break;
165 + case "arm64":
166 + primaryPackageType = BalPrimaryPackageType.ARM64;
167 + break;
168 + default:
169 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, parentElement.Name.LocalName, "PrimaryPackageType", primaryPackageTypeValue, "default", "x86", "x64", "arm64"));
170 break;
172 - }
171 }
172
175 - if (null != prereqInfo.LicenseUrl)
173 + // at the time the extension attribute is parsed, the compiler might not yet have
174 + // parsed the PrereqPackage attribute, so we need to get it directly from the parent element.
175 + var prereqPackage = parentElement.Attribute(this.Namespace + "PrereqPackage");
176 + var prereqInfo = this.GetMbaPrereqInformationSymbol(section, sourceLineNumbers, prereqPackage, packageId);
177 + if (prereqInfo != null)
178 + {
179 + this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, parentElement.Name.LocalName, "PrereqPackage", "yes", "PrimaryPackageType"));
180 + }
181 + else
182 + {
183 + var packageInfo = this.GetBalPackageInfoSymbol(section, sourceLineNumbers, packageId);
184 + packageInfo.PrimaryPackageType = primaryPackageType;
185 + }
186 + break;
187 + }
188 + case "PrereqLicenseFile":
189 + {
190 + // at the time the extension attribute is parsed, the compiler might not yet have
191 + // parsed the PrereqPackage attribute, so we need to get it directly from the parent element.
192 + var prereqPackage = parentElement.Attribute(this.Namespace + "PrereqPackage");
193 + var prereqInfo = this.GetMbaPrereqInformationSymbol(section, sourceLineNumbers, prereqPackage, packageId);
194 + if (prereqInfo == null)
195 + {
196 + this.Messaging.Write(BalErrors.AttributeRequiresPrereqPackage(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseFile"));
197 + }
198 + else if (null != prereqInfo.LicenseUrl)
199 {
200 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseFile", "PrereqLicenseUrl"));
201 }
@@ -181,31 +204,19 @@ namespace WixToolset.Bal
204 prereqInfo.LicenseFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute);
205 }
206 break;
207 + }
208 case "PrereqLicenseUrl":
209 + {
210 + // at the time the extension attribute is parsed, the compiler might not yet have
211 + // parsed the PrereqPackage attribute, so we need to get it directly from the parent element.
212 + var prereqPackage = parentElement.Attribute(this.Namespace + "PrereqPackage");
213 + var prereqInfo = this.GetMbaPrereqInformationSymbol(section, sourceLineNumbers, prereqPackage, packageId);
214
186 - if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out prereqInfo))
215 + if (prereqInfo == null)
216 {
188 - // at the time the extension attribute is parsed, the compiler might not yet have
189 - // parsed the PrereqPackage attribute, so we need to get it directly from the parent element.
190 - var prereqPackage = parentElement.Attribute(this.Namespace + "PrereqPackage");
191 -
192 - if (null != prereqPackage && YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, prereqPackage))
193 - {
194 - prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
195 - {
196 - PackageId = packageId,
197 - });
198 -
199 - this.prereqInfoSymbolsByPackageId.Add(packageId, prereqInfo);
200 - }
201 - else
202 - {
203 - this.Messaging.Write(BalErrors.AttributeRequiresPrereqPackage(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseUrl"));
204 - break;
205 - }
217 + this.Messaging.Write(BalErrors.AttributeRequiresPrereqPackage(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseUrl"));
218 }
207 -
208 - if (null != prereqInfo.LicenseFile)
219 + else if (null != prereqInfo.LicenseFile)
220 {
221 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseUrl", "PrereqLicenseFile"));
222 }
@@ -214,19 +225,9 @@ namespace WixToolset.Bal
225 prereqInfo.LicenseUrl = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute);
226 }
227 break;
228 + }
229 case "PrereqPackage":
218 - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute))
219 - {
220 - if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out _))
221 - {
222 - prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
223 - {
224 - PackageId = packageId,
225 - });
226 -
227 - this.prereqInfoSymbolsByPackageId.Add(packageId, prereqInfo);
228 - }
229 - }
230 + this.GetMbaPrereqInformationSymbol(section, sourceLineNumbers, attribute, packageId);
231 break;
232 default:
233 this.ParseHelper.UnexpectedAttribute(parentElement, attribute);
@@ -300,6 +301,41 @@ namespace WixToolset.Bal
301 }
302 }
303
304 + private WixBalPackageInfoSymbol GetBalPackageInfoSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, string packageId)
305 + {
306 + if (!this.packageInfoSymbolsByPackageId.TryGetValue(packageId, out var packageInfo))
307 + {
308 + packageInfo = section.AddSymbol(new WixBalPackageInfoSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, packageId))
309 + {
310 + PackageId = packageId,
311 + });
312 +
313 + this.packageInfoSymbolsByPackageId.Add(packageId, packageInfo);
314 + }
315 +
316 + return packageInfo;
317 + }
318 +
319 + private WixMbaPrereqInformationSymbol GetMbaPrereqInformationSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute prereqAttribute, string packageId)
320 + {
321 + WixMbaPrereqInformationSymbol prereqInfo = null;
322 +
323 + if (prereqAttribute != null && YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, prereqAttribute))
324 + {
325 + if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out _))
326 + {
327 + prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, packageId))
328 + {
329 + PackageId = packageId,
330 + });
331 +
332 + this.prereqInfoSymbolsByPackageId.Add(packageId, prereqInfo);
333 + }
334 + }
335 +
336 + return prereqInfo;
337 + }
338 +
339 /// <summary>
340 /// Parses a Condition element for Bundles.
341 /// </summary>
@@ -418,6 +454,101 @@ namespace WixToolset.Bal
454 }
455 }
456
457 + private void ParseWixInternalUIBootstrapperApplicationElement(Intermediate intermediate, IntermediateSection section, XElement node)
458 + {
459 + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
460 + WixInternalUIBootstrapperApplicationTheme? theme = null;
461 + string themeFile = null;
462 + string logoFile = null;
463 + string localizationFile = null;
464 +
465 + foreach (var attrib in node.Attributes())
466 + {
467 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
468 + {
469 + switch (attrib.Name.LocalName)
470 + {
471 + case "LogoFile":
472 + logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
473 + break;
474 + case "ThemeFile":
475 + themeFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
476 + break;
477 + case "LocalizationFile":
478 + localizationFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
479 + break;
480 + case "Theme":
481 + var themeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
482 + switch (themeValue)
483 + {
484 + case "none":
485 + theme = WixInternalUIBootstrapperApplicationTheme.None;
486 + break;
487 + case "standard":
488 + theme = WixInternalUIBootstrapperApplicationTheme.Standard;
489 + break;
490 + default:
491 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Theme", themeValue, "none", "standard"));
492 + theme = WixInternalUIBootstrapperApplicationTheme.Unknown;
493 + break;
494 + }
495 + break;
496 + default:
497 + this.ParseHelper.UnexpectedAttribute(node, attrib);
498 + break;
499 + }
500 + }
501 + else
502 + {
503 + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
504 + }
505 + }
506 +
507 + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
508 +
509 + if (!theme.HasValue)
510 + {
511 + theme = WixInternalUIBootstrapperApplicationTheme.Standard;
512 + }
513 +
514 + if (!this.Messaging.EncounteredError)
515 + {
516 + if (!String.IsNullOrEmpty(logoFile))
517 + {
518 + section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixIuibaLogo"))
519 + {
520 + Value = logoFile,
521 + });
522 + }
523 +
524 + if (!String.IsNullOrEmpty(themeFile))
525 + {
526 + section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixIuibaThemeXml"))
527 + {
528 + Value = themeFile,
529 + });
530 + }
531 +
532 + if (!String.IsNullOrEmpty(localizationFile))
533 + {
534 + section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixIuibaThemeWxl"))
535 + {
536 + Value = localizationFile,
537 + });
538 + }
539 +
540 + var baId = "WixInternalUIBootstrapperApplication";
541 + switch (theme)
542 + {
543 + case WixInternalUIBootstrapperApplicationTheme.Standard:
544 + baId = "WixInternalUIBootstrapperApplication.Standard";
545 + break;
546 + }
547 +
548 + this.CreateBARef(section, sourceLineNumbers, node, baId);
549 + }
550 + }
551 +
552 /// <summary>
553 /// Parses a WixStandardBootstrapperApplication element for Bundles.
554 /// </summary>
src/ext/Bal/wixext/BalErrors.cs
+48
@@ -18,11 +18,41 @@ namespace WixToolset.Bal
18 return Message(sourceLineNumbers, Ids.BAFunctionsPayloadRequiredInUXContainer, "The BAFunctions DLL Payload element must be located inside the BootstrapperApplication container.");
19 }
20
21 + public static Message IuibaNonMsiPrimaryPackage(SourceLineNumber sourceLineNumbers)
22 + {
23 + return Message(sourceLineNumbers, Ids.IuibaNonMsiPrimaryPackage, "When using WixInternalUIBootstrapperApplication, each primary package must be an MsiPackage.");
24 + }
25 +
26 + public static Message IuibaNonPermanentNonPrimaryPackage(SourceLineNumber sourceLineNumbers)
27 + {
28 + return Message(sourceLineNumbers, Ids.IuibaNonPermanentNonPrimaryPackage, "When using WixInternalUIBootstrapperApplication, packages must either be non-permanent and have the bal:PrimaryPackageType attribute, or be permanent and have the bal:PrereqPackage attribute set to 'yes'.");
29 + }
30 +
31 + public static Message IuibaNonPermanentPrereqPackage(SourceLineNumber sourceLineNumbers)
32 + {
33 + return Message(sourceLineNumbers, Ids.IuibaNonPermanentPrereqPackage, "When using WixInternalUIBootstrapperApplication and bal:PrereqPackage is set to 'yes', the package must be permanent.");
34 + }
35 +
36 + public static Message IuibaPermanentPrimaryPackageType(SourceLineNumber sourceLineNumbers)
37 + {
38 + return Message(sourceLineNumbers, Ids.IuibaPermanentPrimaryPackageType, "When using WixInternalUIBootstrapperApplication, packages with the bal:PrimaryPackageType attribute must not be permanent.");
39 + }
40 +
41 + public static Message IuibaPrimaryPackageEnableFeatureSelection(SourceLineNumber sourceLineNumbers)
42 + {
43 + return Message(sourceLineNumbers, Ids.IuibaPrimaryPackageEnableFeatureSelection, "When using WixInternalUIBootstrapperApplication, primary packages must not have feature selection enabled because it interferes with the user selecting feature through the MSI UI.");
44 + }
45 +
46 public static Message MissingDNCPrereq()
47 {
48 return Message(null, Ids.MissingDNCPrereq, "There must be at least one PrereqPackage when using the DotNetCoreBootstrapperApplicationHost with SelfContainedDeployment set to \"no\".");
49 }
50
51 + public static Message MissingIUIPrimaryPackage()
52 + {
53 + return Message(null, Ids.MissingIUIPrimaryPackage, "When using WixInternalUIBootstrapperApplication, there must be one package with bal:PrimaryPackageType=\"default\".");
54 + }
55 +
56 public static Message MissingMBAPrereq()
57 {
58 return Message(null, Ids.MissingMBAPrereq, "There must be at least one PrereqPackage when using the ManagedBootstrapperApplicationHost.\nThis is typically done by using the WixNetFxExtension and referencing one of the NetFxAsPrereq package groups.");
@@ -38,6 +68,16 @@ namespace WixToolset.Bal
68 return Message(sourceLineNumbers, Ids.MultiplePrereqLicenses, "There may only be one package in the bundle that has either the PrereqLicenseFile attribute or the PrereqLicenseUrl attribute.");
69 }
70
71 + public static Message MultiplePrimaryPackageType(SourceLineNumber sourceLineNumbers, string primaryPackageType)
72 + {
73 + return Message(sourceLineNumbers, Ids.MultiplePrimaryPackageType, "There may only be one package in the bundle with PrimaryPackageType of '{0}'.", primaryPackageType);
74 + }
75 +
76 + public static Message MultiplePrimaryPackageType2(SourceLineNumber sourceLineNumbers)
77 + {
78 + return Message(sourceLineNumbers, Ids.MultiplePrimaryPackageType2, "The location of the package related to the previous error.");
79 + }
80 +
81 public static Message NonUpperCaseOverridableVariable(SourceLineNumber sourceLineNumbers, string name, string expectedName)
82 {
83 return Message(sourceLineNumbers, Ids.NonUpperCaseOverridableVariable, "Overridable variable '{0}' must be '{1}' with Bundle/@CommandLineVariables value 'upperCase'.", name, expectedName);
@@ -62,6 +102,14 @@ namespace WixToolset.Bal
102 BAFunctionsPayloadRequiredInUXContainer = 6805,
103 MissingDNCPrereq = 6806,
104 NonUpperCaseOverridableVariable = 6807,
105 + MissingIUIPrimaryPackage = 6808,
106 + MultiplePrimaryPackageType = 6809,
107 + MultiplePrimaryPackageType2 = 6810,
108 + IuibaNonPermanentNonPrimaryPackage = 6811,
109 + IuibaNonPermanentPrereqPackage = 6812,
110 + IuibaPermanentPrimaryPackageType = 6813,
111 + IuibaNonMsiPrimaryPackage = 6814,
112 + IuibaPrimaryPackageEnableFeatureSelection = 6815,
113 }
114 }
115 }
src/ext/Bal/wixext/BalWarnings.cs
+24
@@ -8,6 +8,26 @@ namespace WixToolset.Bal
8
9 public static class BalWarnings
10 {
11 + public static Message IuibaForceCachePrereq(SourceLineNumber sourceLineNumbers)
12 + {
13 + return Message(sourceLineNumbers, Ids.IuibaForceCachePrereq, "WixInternalUIBootstrapperApplication does not support the value of 'force' for Cache on prereq packages. Prereq packages are only cached when they need to be installed.");
14 + }
15 +
16 + public static Message IuibaPrereqPackageAfterPrimaryPackage(SourceLineNumber sourceLineNumbers)
17 + {
18 + return Message(sourceLineNumbers, Ids.IuibaPrereqPackageAfterPrimaryPackage, "When using WixInternalUIBootstrapperApplication, all prereq packages should be before the primary package in the chain. The prereq packages are always installed before the primary package.");
19 + }
20 +
21 + public static Message IuibaPrimaryPackageDisplayInternalUICondition(SourceLineNumber sourceLineNumbers)
22 + {
23 + return Message(sourceLineNumbers, Ids.IuibaPrimaryPackageDisplayInternalUICondition, "WixInternalUIBootstrapperApplication ignores DisplayInternalUICondition for the primary package so that the MSI UI is always shown.");
24 + }
25 +
26 + public static Message IuibaPrimaryPackageInstallCondition(SourceLineNumber sourceLineNumbers)
27 + {
28 + return Message(sourceLineNumbers, Ids.IuibaPrimaryPackageInstallCondition, "WixInternalUIBootstrapperApplication ignores InstallCondition for the primary package so that the MSI UI is always shown.");
29 + }
30 +
31 public static Message UnmarkedBAFunctionsDLL(SourceLineNumber sourceLineNumbers)
32 {
33 return Message(sourceLineNumbers, Ids.UnmarkedBAFunctionsDLL, "WixStandardBootstrapperApplication doesn't automatically load BAFunctions.dll. Use the bal:BAFunctions attribute to indicate that it should be loaded.");
@@ -26,6 +46,10 @@ namespace WixToolset.Bal
46 public enum Ids
47 {
48 UnmarkedBAFunctionsDLL = 6501,
49 + IuibaForceCachePrereq = 6502,
50 + IuibaPrimaryPackageInstallCondition = 6503,
51 + IuibaPrimaryPackageDisplayInternalUICondition = 6504,
52 + IuibaPrereqPackageAfterPrimaryPackage = 6505,
53 }
54 }
55 }
src/ext/Bal/wixext/Symbols/WixBalPackageInfoSymbol.cs
+17
@@ -13,6 +13,7 @@ namespace WixToolset.Bal
13 {
14 new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.PackageId), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.DisplayInternalUICondition), IntermediateFieldType.String),
16 + new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.PrimaryPackageType), IntermediateFieldType.Number),
17 },
18 typeof(WixBalPackageInfoSymbol));
19 }
@@ -26,6 +27,16 @@ namespace WixToolset.Bal.Symbols
27 {
28 PackageId,
29 DisplayInternalUICondition,
30 + PrimaryPackageType,
31 + }
32 +
33 + public enum BalPrimaryPackageType
34 + {
35 + None,
36 + Default,
37 + X86,
38 + X64,
39 + ARM64,
40 }
41
42 public class WixBalPackageInfoSymbol : IntermediateSymbol
@@ -51,5 +62,11 @@ namespace WixToolset.Bal.Symbols
62 get => this.Fields[(int)WixBalPackageInfoSymbolFields.DisplayInternalUICondition].AsString();
63 set => this.Set((int)WixBalPackageInfoSymbolFields.DisplayInternalUICondition, value);
64 }
65 +
66 + public BalPrimaryPackageType PrimaryPackageType
67 + {
68 + get => (BalPrimaryPackageType)this.Fields[(int)WixBalPackageInfoSymbolFields.PrimaryPackageType].AsNumber();
69 + set => this.Set((int)WixBalPackageInfoSymbolFields.PrimaryPackageType, (int)value);
70 + }
71 }
72 }
src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp new
+918
@@ -0,0 +1,918 @@
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 "precomp.h"
4 +#include "BalBaseBootstrapperApplicationProc.h"
5 +#include "BalBaseBootstrapperApplication.h"
6 +
7 +static const LPCWSTR WIXIUIBA_WINDOW_CLASS = L"WixInternalUIBA";
8 +
9 +enum WM_WIXIUIBA
10 +{
11 + WM_WIXIUIBA_DETECT_PACKAGES = WM_APP + 100,
12 + WM_WIXIUIBA_PLAN_PACKAGES,
13 + WM_WIXIUIBA_APPLY_PACKAGES,
14 + WM_WIXIUIBA_DETECT_FOR_CLEANUP,
15 + WM_WIXIUIBA_PLAN_PACKAGES_FOR_CLEANUP,
16 +};
17 +
18 +
19 +class CWixInternalUIBootstrapperApplication : public CBalBaseBootstrapperApplication
20 +{
21 +public: // IBootstrapperApplication
22 + virtual STDMETHODIMP OnStartup()
23 + {
24 + HRESULT hr = S_OK;
25 + DWORD dwUIThreadId = 0;
26 +
27 + // create UI thread
28 + m_hUiThread = ::CreateThread(NULL, 0, UiThreadProc, this, 0, &dwUIThreadId);
29 + if (!m_hUiThread)
30 + {
31 + BalExitWithLastError(hr, "Failed to create UI thread.");
32 + }
33 +
34 + LExit:
35 + return hr;
36 + }
37 +
38 +
39 + virtual STDMETHODIMP OnShutdown(
40 + __inout BOOTSTRAPPER_SHUTDOWN_ACTION* pAction
41 + )
42 + {
43 + // wait for UI thread to terminate
44 + if (m_hUiThread)
45 + {
46 + ::WaitForSingleObject(m_hUiThread, INFINITE);
47 + ReleaseHandle(m_hUiThread);
48 + }
49 +
50 + if (m_fFailedToLoadPackage)
51 + {
52 + Assert(FAILED(m_hrFinal));
53 + m_pPrereqData->hrFatalError = m_hrFinal;
54 + BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load primary package as the BA. The bootstrapper application will be reloaded to show the error.");
55 + *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER;
56 + }
57 +
58 + return S_OK;
59 + }
60 +
61 +
62 + virtual STDMETHODIMP OnDetectPackageComplete(
63 + __in_z LPCWSTR wzPackageId,
64 + __in HRESULT hrStatus,
65 + __in BOOTSTRAPPER_PACKAGE_STATE state,
66 + __in BOOL fCached
67 + )
68 + {
69 + BAL_INFO_PACKAGE* pPackage = NULL;
70 +
71 + if (SUCCEEDED(hrStatus) && SUCCEEDED(BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage)) &&
72 + BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT == pPackage->primaryPackageType)
73 + {
74 + BOOL fInstalled = BOOTSTRAPPER_PACKAGE_STATE_ABSENT < state;
75 +
76 + // Maybe modify the action state if the primary package is or is not already installed.
77 + if (fInstalled && BOOTSTRAPPER_ACTION_INSTALL == m_command.action)
78 + {
79 + m_command.action = BOOTSTRAPPER_ACTION_MODIFY;
80 + }
81 + else if (!fInstalled && (BOOTSTRAPPER_ACTION_MODIFY == m_command.action || BOOTSTRAPPER_ACTION_REPAIR == m_command.action))
82 + {
83 + m_command.action = BOOTSTRAPPER_ACTION_INSTALL;
84 + }
85 +
86 + if (m_fApplied && !fInstalled && fCached)
87 + {
88 + m_fAutomaticRemoval = TRUE;
89 + }
90 + }
91 +
92 + return __super::OnDetectPackageComplete(wzPackageId, hrStatus, state, fCached);
93 + }
94 +
95 +
96 + virtual STDMETHODIMP OnDetectComplete(
97 + __in HRESULT hrStatus,
98 + __in BOOL fEligibleForCleanup
99 + )
100 + {
101 + if (m_fAutomaticRemoval && SUCCEEDED(hrStatus))
102 + {
103 + ::PostMessageW(m_hWnd, WM_WIXIUIBA_PLAN_PACKAGES_FOR_CLEANUP, 0, BOOTSTRAPPER_ACTION_UNINSTALL);
104 + ExitFunction();
105 + }
106 + else if (m_fApplied)
107 + {
108 + ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
109 + ExitFunction();
110 + }
111 +
112 + // If we're performing an action that modifies machine state then evaluate conditions.
113 + BOOL fEvaluateConditions = SUCCEEDED(hrStatus) &&
114 + (BOOTSTRAPPER_ACTION_LAYOUT < m_command.action && BOOTSTRAPPER_ACTION_UPDATE_REPLACE > m_command.action);
115 +
116 + if (fEvaluateConditions)
117 + {
118 + hrStatus = EvaluateConditions();
119 + }
120 +
121 + if (SUCCEEDED(hrStatus))
122 + {
123 + ::PostMessageW(m_hWnd, WM_WIXIUIBA_PLAN_PACKAGES, 0, m_command.action);
124 + }
125 + else
126 + {
127 + SetLoadPackageFailure(hrStatus);
128 + }
129 +
130 + LExit:
131 + return __super::OnDetectComplete(hrStatus, fEligibleForCleanup);
132 + }
133 +
134 +
135 + virtual STDMETHODIMP OnPlanPackageBegin(
136 + __in_z LPCWSTR wzPackageId,
137 + __in BOOTSTRAPPER_PACKAGE_STATE state,
138 + __in BOOL fCached,
139 + __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition,
140 + __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition,
141 + __in BOOTSTRAPPER_REQUEST_STATE recommendedState,
142 + __in BOOTSTRAPPER_CACHE_TYPE recommendedCacheType,
143 + __inout BOOTSTRAPPER_REQUEST_STATE* pRequestState,
144 + __inout BOOTSTRAPPER_CACHE_TYPE* pRequestedCacheType,
145 + __inout BOOL* pfCancel
146 + )
147 + {
148 + HRESULT hr = S_OK;
149 + BAL_INFO_PACKAGE* pPackage = NULL;
150 +
151 + hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
152 + if (FAILED(hr))
153 + {
154 + // Non-chain package, keep default.
155 + }
156 + else if (BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT != pPackage->primaryPackageType)
157 + {
158 + // Only the primary package should be cached or executed.
159 + if (BOOTSTRAPPER_CACHE_TYPE_FORCE == *pRequestedCacheType)
160 + {
161 + *pRequestedCacheType = BOOTSTRAPPER_CACHE_TYPE_KEEP;
162 + }
163 +
164 + *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
165 + }
166 + else if (BOOTSTRAPPER_DISPLAY_FULL == m_command.display && !m_fAutomaticRemoval)
167 + {
168 + // Make sure the MSI UI is shown regardless of the current state of the package.
169 + *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR;
170 + }
171 +
172 + return __super::OnPlanPackageBegin(wzPackageId, state, fCached, installCondition, repairCondition, recommendedState, recommendedCacheType, pRequestState, pRequestedCacheType, pfCancel);
173 + }
174 +
175 +
176 + virtual STDMETHODIMP OnPlanMsiPackage(
177 + __in_z LPCWSTR wzPackageId,
178 + __in BOOL fExecute,
179 + __in BOOTSTRAPPER_ACTION_STATE action,
180 + __in BOOTSTRAPPER_MSI_FILE_VERSIONING recommendedFileVersioning,
181 + __inout BOOL* pfCancel,
182 + __inout BURN_MSI_PROPERTY* pActionMsiProperty,
183 + __inout INSTALLUILEVEL* pUiLevel,
184 + __inout BOOL* pfDisableExternalUiHandler,
185 + __inout BOOTSTRAPPER_MSI_FILE_VERSIONING* pFileVersioning
186 + )
187 + {
188 + INSTALLUILEVEL uiLevel = INSTALLUILEVEL_NOCHANGE;
189 +
190 + if (m_fAutomaticRemoval)
191 + {
192 + ExitFunction();
193 + }
194 +
195 + switch (m_command.display)
196 + {
197 + case BOOTSTRAPPER_DISPLAY_FULL:
198 + uiLevel = INSTALLUILEVEL_FULL;
199 + break;
200 +
201 + case BOOTSTRAPPER_DISPLAY_PASSIVE:
202 + uiLevel = INSTALLUILEVEL_REDUCED;
203 + break;
204 + }
205 +
206 + if (INSTALLUILEVEL_NOCHANGE != uiLevel)
207 + {
208 + *pUiLevel = uiLevel;
209 + }
210 +
211 + *pActionMsiProperty = BURN_MSI_PROPERTY_NONE;
212 + *pfDisableExternalUiHandler = TRUE;
213 +
214 + LExit:
215 + return __super::OnPlanMsiPackage(wzPackageId, fExecute, action, recommendedFileVersioning, pfCancel, pActionMsiProperty, pUiLevel, pfDisableExternalUiHandler, pFileVersioning);
216 + }
217 +
218 +
219 + virtual STDMETHODIMP OnPlanComplete(
220 + __in HRESULT hrStatus
221 + )
222 + {
223 + if (SUCCEEDED(hrStatus))
224 + {
225 + ::PostMessageW(m_hWnd, WM_WIXIUIBA_APPLY_PACKAGES, 0, 0);
226 + }
227 + else if (m_fAutomaticRemoval)
228 + {
229 + ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
230 + }
231 + else
232 + {
233 + SetLoadPackageFailure(hrStatus);
234 + }
235 +
236 + return __super::OnPlanComplete(hrStatus);
237 + }
238 +
239 +
240 + virtual STDMETHODIMP OnApplyBegin(
241 + __in DWORD dwPhaseCount,
242 + __inout BOOL* pfCancel
243 + )
244 + {
245 + m_fApplying = TRUE;
246 + return __super::OnApplyBegin(dwPhaseCount, pfCancel);
247 + }
248 +
249 +
250 + virtual STDMETHODIMP OnCacheComplete(
251 + __in HRESULT hrStatus
252 + )
253 + {
254 + if (FAILED(hrStatus) && !m_fAutomaticRemoval)
255 + {
256 + SetLoadPackageFailure(hrStatus);
257 + }
258 +
259 + return __super::OnCacheComplete(hrStatus);
260 + }
261 +
262 +
263 + virtual STDMETHODIMP OnExecuteBegin(
264 + __in DWORD cExecutingPackages,
265 + __in BOOL* pfCancel
266 + )
267 + {
268 + m_pEngine->CloseSplashScreen();
269 +
270 + return __super::OnExecuteBegin(cExecutingPackages, pfCancel);
271 + }
272 +
273 +
274 + virtual STDMETHODIMP OnApplyComplete(
275 + __in HRESULT hrStatus,
276 + __in BOOTSTRAPPER_APPLY_RESTART restart,
277 + __in BOOTSTRAPPER_APPLYCOMPLETE_ACTION recommendation,
278 + __inout BOOTSTRAPPER_APPLYCOMPLETE_ACTION* pAction
279 + )
280 + {
281 + HRESULT hr = __super::OnApplyComplete(hrStatus, restart, recommendation, pAction);
282 +
283 + *pAction = BOOTSTRAPPER_APPLYCOMPLETE_ACTION_NONE;
284 + m_fApplying = FALSE;
285 +
286 + if (m_fAutomaticRemoval)
287 + {
288 + ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
289 + }
290 + else
291 + {
292 + m_restartResult = restart; // remember the restart result so we return the correct error code.
293 + m_fApplied = TRUE;
294 +
295 + if (FAILED(hrStatus))
296 + {
297 + m_hrFinal = hrStatus;
298 + }
299 +
300 + ::PostMessageW(m_hWnd, WM_WIXIUIBA_DETECT_FOR_CLEANUP, 0, 0);
301 + }
302 +
303 + return hr;
304 + }
305 +
306 +
307 +public: //CBalBaseBootstrapperApplication
308 + virtual STDMETHODIMP Initialize(
309 + __in const BOOTSTRAPPER_CREATE_ARGS* pCreateArgs
310 + )
311 + {
312 + HRESULT hr = S_OK;
313 +
314 + hr = __super::Initialize(pCreateArgs);
315 + BalExitOnFailure(hr, "CBalBaseBootstrapperApplication initialization failed.");
316 +
317 + memcpy_s(&m_command, sizeof(m_command), pCreateArgs->pCommand, sizeof(BOOTSTRAPPER_COMMAND));
318 + memcpy_s(&m_createArgs, sizeof(m_createArgs), pCreateArgs, sizeof(BOOTSTRAPPER_CREATE_ARGS));
319 + m_createArgs.pCommand = &m_command;
320 +
321 + LExit:
322 + return hr;
323 + }
324 +
325 + void Uninitialize(
326 + __in const BOOTSTRAPPER_DESTROY_ARGS* /*pArgs*/,
327 + __in BOOTSTRAPPER_DESTROY_RESULTS* /*pResults*/
328 + )
329 + {
330 + }
331 +
332 +
333 +private:
334 + //
335 + // UiThreadProc - entrypoint for UI thread.
336 + //
337 + static DWORD WINAPI UiThreadProc(
338 + __in LPVOID pvContext
339 + )
340 + {
341 + HRESULT hr = S_OK;
342 + CWixInternalUIBootstrapperApplication* pThis = (CWixInternalUIBootstrapperApplication*)pvContext;
343 + BOOL fComInitialized = FALSE;
344 + BOOL fRet = FALSE;
345 + MSG msg = { };
346 + DWORD dwQuit = 0;
347 +
348 + // Initialize COM and theme.
349 + hr = ::CoInitialize(NULL);
350 + BalExitOnFailure(hr, "Failed to initialize COM.");
351 + fComInitialized = TRUE;
352 +
353 + hr = pThis->InitializeData();
354 + BalExitOnFailure(hr, "Failed to initialize data in bootstrapper application.");
355 +
356 + // Create main window.
357 + hr = pThis->CreateMainWindow();
358 + BalExitOnFailure(hr, "Failed to create main window.");
359 +
360 + ::PostMessageW(pThis->m_hWnd, WM_WIXIUIBA_DETECT_PACKAGES, 0, 0);
361 +
362 + // message pump
363 + while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
364 + {
365 + if (-1 == fRet)
366 + {
367 + hr = E_UNEXPECTED;
368 + BalExitOnFailure(hr, "Unexpected return value from message pump.");
369 + }
370 + else if (!::IsDialogMessageW(pThis->m_hWnd, &msg))
371 + {
372 + ::TranslateMessage(&msg);
373 + ::DispatchMessageW(&msg);
374 + }
375 + }
376 +
377 + // Succeeded thus far, check to see if anything went wrong while actually
378 + // executing changes.
379 + if (FAILED(pThis->m_hrFinal))
380 + {
381 + hr = pThis->m_hrFinal;
382 + }
383 + else if (pThis->CheckCanceled())
384 + {
385 + hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
386 + }
387 +
388 + LExit:
389 + // destroy main window
390 + pThis->DestroyMainWindow();
391 +
392 + if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->m_restartResult)
393 + {
394 + dwQuit = ERROR_SUCCESS_REBOOT_INITIATED;
395 + }
396 + else if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == pThis->m_restartResult)
397 + {
398 + dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED;
399 + }
400 + else if (SEVERITY_ERROR == HRESULT_SEVERITY(hr) && FACILITY_WIN32 == HRESULT_FACILITY(hr))
401 + {
402 + // Convert Win32 HRESULTs back to the error code.
403 + dwQuit = HRESULT_CODE(hr);
404 + }
405 + else
406 + {
407 + dwQuit = hr;
408 + }
409 +
410 + // initiate engine shutdown
411 + pThis->m_pEngine->Quit(dwQuit);
412 +
413 + // uninitialize COM
414 + if (fComInitialized)
415 + {
416 + ::CoUninitialize();
417 + }
418 +
419 + return hr;
420 + }
421 +
422 +
423 + //
424 + // InitializeData - initializes all the package and prerequisite information.
425 + //
426 + HRESULT InitializeData()
427 + {
428 + HRESULT hr = S_OK;
429 + IXMLDOMDocument* pixdManifest = NULL;
430 +
431 + hr = BalManifestLoad(m_hModule, &pixdManifest);
432 + BalExitOnFailure(hr, "Failed to load bootstrapper application manifest.");
433 +
434 + hr = BalInfoParseFromXml(&m_Bundle, pixdManifest);
435 + BalExitOnFailure(hr, "Failed to load bundle information.");
436 +
437 + hr = EnsureSinglePrimaryPackage();
438 + BalExitOnFailure(hr, "Failed to ensure single primary package.");
439 +
440 + hr = ProcessCommandLine();
441 + ExitOnFailure(hr, "Unknown commandline parameters.");
442 +
443 + hr = BalConditionsParseFromXml(&m_Conditions, pixdManifest, NULL);
444 + BalExitOnFailure(hr, "Failed to load conditions from XML.");
445 +
446 + LExit:
447 + ReleaseObject(pixdManifest);
448 +
449 + return hr;
450 + }
451 +
452 +
453 + //
454 + // ProcessCommandLine - process the provided command line arguments.
455 + //
456 + HRESULT ProcessCommandLine()
457 + {
458 + HRESULT hr = S_OK;
459 + int argc = 0;
460 + LPWSTR* argv = NULL;
461 +
462 + argc = m_BalInfoCommand.cUnknownArgs;
463 + argv = m_BalInfoCommand.rgUnknownArgs;
464 +
465 + for (int i = 0; i < argc; ++i)
466 + {
467 + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Ignoring unknown argument: %ls", argv[i]);
468 + }
469 +
470 + hr = BalSetOverridableVariablesFromEngine(&m_Bundle.overridableVariables, &m_BalInfoCommand, m_pEngine);
471 + BalExitOnFailure(hr, "Failed to set overridable variables from the command line.");
472 +
473 + LExit:
474 + return hr;
475 + }
476 +
477 + HRESULT EnsureSinglePrimaryPackage()
478 + {
479 + HRESULT hr = S_OK;
480 + BAL_INFO_PACKAGE* pDefaultPackage = NULL;
481 + BOOL fPrimaryArchSpecific = FALSE;
482 + USHORT usNativeMachine = 0;
483 + BAL_INFO_PRIMARY_PACKAGE_TYPE nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_NONE;
484 +
485 + hr = ProcNativeMachine(::GetCurrentProcess(), &usNativeMachine);
486 + BalExitOnFailure(hr, "Failed to get native machine value.");
487 +
488 + if (S_FALSE != hr)
489 + {
490 + switch (usNativeMachine)
491 + {
492 + case IMAGE_FILE_MACHINE_I386:
493 + nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X86;
494 + break;
495 + case IMAGE_FILE_MACHINE_AMD64:
496 + nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X64;
497 + break;
498 + case IMAGE_FILE_MACHINE_ARM64:
499 + nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_ARM64;
500 + break;
501 + }
502 + }
503 + else
504 + {
505 +#if !defined(_WIN64)
506 + BOOL fIsWow64 = FALSE;
507 +
508 + ProcWow64(::GetCurrentProcess(), &fIsWow64);
509 + if (!fIsWow64)
510 + {
511 + nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X86;
512 + }
513 + else
514 +#endif
515 + {
516 + nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X64;
517 + }
518 + }
519 +
520 + for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
521 + {
522 + BAL_INFO_PACKAGE* pPackage = m_Bundle.packages.rgPackages + i;
523 +
524 + if (BAL_INFO_PRIMARY_PACKAGE_TYPE_NONE == pPackage->primaryPackageType)
525 + {
526 + // Skip.
527 + }
528 + else if (nativeType == pPackage->primaryPackageType)
529 + {
530 + if (fPrimaryArchSpecific)
531 + {
532 + BalExitWithRootFailure(hr, E_INVALIDDATA, "Bundle contains multiple primary packages for same architecture: %u.", nativeType);
533 + }
534 +
535 + pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT;
536 + fPrimaryArchSpecific = TRUE;
537 + }
538 + else if (BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT == pPackage->primaryPackageType)
539 + {
540 + if (pDefaultPackage)
541 + {
542 + BalExitWithRootFailure(hr, E_INVALIDDATA, "Bundle contains multiple default primary packages.");
543 + }
544 +
545 + pDefaultPackage = pPackage;
546 + }
547 + }
548 +
549 + BalExitOnNull(pDefaultPackage, hr, E_INVALIDSTATE, "Bundle did not contain default primary package.");
550 +
551 + if (fPrimaryArchSpecific)
552 + {
553 + pDefaultPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_NONE;
554 + }
555 +
556 + LExit:
557 + return hr;
558 + }
559 +
560 +
561 + //
562 + // CreateMainWindow - creates the main install window.
563 + //
564 + HRESULT CreateMainWindow()
565 + {
566 + HRESULT hr = S_OK;
567 + WNDCLASSW wc = { };
568 + DWORD dwWindowStyle = WS_POPUP;
569 +
570 + wc.lpfnWndProc = CWixInternalUIBootstrapperApplication::WndProc;
571 + wc.hInstance = m_hModule;
572 + wc.lpszClassName = WIXIUIBA_WINDOW_CLASS;
573 +
574 + if (!::RegisterClassW(&wc))
575 + {
576 + ExitWithLastError(hr, "Failed to register window.");
577 + }
578 +
579 + m_fRegistered = TRUE;
580 +
581 + // If the UI should be visible, allow it to be visible and activated so we are the foreground window.
582 + // This allows the UAC prompt and MSI UI to automatically be activated.
583 + if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
584 + {
585 + dwWindowStyle |= WS_VISIBLE;
586 + }
587 +
588 + m_hWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW, wc.lpszClassName, NULL, dwWindowStyle, 0, 0, 0, 0, HWND_DESKTOP, NULL, m_hModule, this);
589 + ExitOnNullWithLastError(m_hWnd, hr, "Failed to create window.");
590 +
591 + LExit:
592 + return hr;
593 + }
594 +
595 + //
596 + // DestroyMainWindow - clean up all the window registration.
597 + //
598 + void DestroyMainWindow()
599 + {
600 + if (::IsWindow(m_hWnd))
601 + {
602 + ::DestroyWindow(m_hWnd);
603 + m_hWnd = NULL;
604 + }
605 +
606 + if (m_fRegistered)
607 + {
608 + ::UnregisterClassW(WIXIUIBA_WINDOW_CLASS, m_hModule);
609 + m_fRegistered = FALSE;
610 + }
611 + }
612 +
613 + //
614 + // WndProc - standard windows message handler.
615 + //
616 + static LRESULT CALLBACK WndProc(
617 + __in HWND hWnd,
618 + __in UINT uMsg,
619 + __in WPARAM wParam,
620 + __in LPARAM lParam
621 + )
622 + {
623 +#pragma warning(suppress:4312)
624 + CWixInternalUIBootstrapperApplication* pBA = reinterpret_cast<CWixInternalUIBootstrapperApplication*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA));
625 +
626 + switch (uMsg)
627 + {
628 + case WM_NCCREATE:
629 + {
630 + LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
631 + pBA = reinterpret_cast<CWixInternalUIBootstrapperApplication*>(lpcs->lpCreateParams);
632 +#pragma warning(suppress:4244)
633 + ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pBA));
634 + }
635 + break;
636 +
637 + case WM_NCDESTROY:
638 + {
639 + LRESULT lres = ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
640 + ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, 0);
641 + ::PostQuitMessage(0);
642 + return lres;
643 + }
644 +
645 + case WM_CLOSE:
646 + // If the user chose not to close, do *not* let the default window proc handle the message.
647 + if (!pBA->OnClose())
648 + {
649 + return 0;
650 + }
651 + break;
652 +
653 + case WM_WIXIUIBA_DETECT_PACKAGES: __fallthrough;
654 + case WM_WIXIUIBA_DETECT_FOR_CLEANUP:
655 + pBA->OnDetect();
656 + return 0;
657 +
658 + case WM_WIXIUIBA_PLAN_PACKAGES:
659 + case WM_WIXIUIBA_PLAN_PACKAGES_FOR_CLEANUP:
660 + pBA->OnPlan(static_cast<BOOTSTRAPPER_ACTION>(lParam));
661 + return 0;
662 +
663 + case WM_WIXIUIBA_APPLY_PACKAGES:
664 + pBA->OnApply();
665 + return 0;
666 + }
667 +
668 + return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
669 + }
670 +
671 +
672 + //
673 + // OnDetect - start the processing of packages.
674 + //
675 + void OnDetect()
676 + {
677 + HRESULT hr = S_OK;
678 +
679 + hr = m_pEngine->Detect();
680 + BalExitOnFailure(hr, "Failed to start detecting chain.");
681 +
682 + LExit:
683 + if (FAILED(hr))
684 + {
685 + SetLoadPackageFailure(hr);
686 + }
687 + }
688 +
689 +
690 + //
691 + // OnPlan - plan the detected changes.
692 + //
693 + void OnPlan(
694 + __in BOOTSTRAPPER_ACTION action
695 + )
696 + {
697 + HRESULT hr = S_OK;
698 +
699 + m_plannedAction = action;
700 +
701 + hr = m_pEngine->Plan(action);
702 + BalExitOnFailure(hr, "Failed to start planning packages.");
703 +
704 + LExit:
705 + if (FAILED(hr))
706 + {
707 + SetLoadPackageFailure(hr);
708 + }
709 + }
710 +
711 +
712 + //
713 + // OnApply - apply the packages.
714 + //
715 + void OnApply()
716 + {
717 + HRESULT hr = S_OK;
718 +
719 + hr = m_pEngine->Apply(m_hWnd);
720 + BalExitOnFailure(hr, "Failed to start applying packages.");
721 +
722 + LExit:
723 + if (FAILED(hr))
724 + {
725 + SetLoadPackageFailure(hr);
726 + }
727 + }
728 +
729 +
730 + //
731 + // OnClose - called when the window is trying to be closed.
732 + //
733 + BOOL OnClose()
734 + {
735 + BOOL fClose = FALSE;
736 +
737 + // If we've already applied, just close.
738 + if (m_fApplied)
739 + {
740 + fClose = TRUE;
741 + }
742 + else
743 + {
744 + PromptCancel(m_hWnd, TRUE, NULL, NULL);
745 +
746 + // If we're inside Apply then we never close, we just cancel to let rollback occur.
747 + fClose = !m_fApplying;
748 + }
749 +
750 + return fClose;
751 + }
752 +
753 +
754 + HRESULT EvaluateConditions()
755 + {
756 + HRESULT hr = S_OK;
757 + BOOL fResult = FALSE;
758 +
759 + for (DWORD i = 0; i < m_Conditions.cConditions; ++i)
760 + {
761 + BAL_CONDITION* pCondition = m_Conditions.rgConditions + i;
762 +
763 + hr = BalConditionEvaluate(pCondition, m_pEngine, &fResult, &m_sczFailedMessage);
764 + BalExitOnFailure(hr, "Failed to evaluate condition.");
765 +
766 + if (!fResult)
767 + {
768 + hr = E_WIXSTDBA_CONDITION_FAILED;
769 + BalExitOnFailure(hr, "%ls", m_sczFailedMessage);
770 + }
771 + }
772 +
773 + ReleaseNullStrSecure(m_sczFailedMessage);
774 +
775 + LExit:
776 + return hr;
777 + }
778 +
779 +
780 + void SetLoadPackageFailure(
781 + __in HRESULT hrStatus
782 + )
783 + {
784 + Assert(FAILED(hrStatus));
785 +
786 + if (!m_fApplied)
787 + {
788 + m_hrFinal = hrStatus;
789 + m_fFailedToLoadPackage = TRUE;
790 + }
791 +
792 + // Quietly exit.
793 + ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
794 + }
795 +
796 +
797 +public:
798 + //
799 + // Constructor - initialize member variables.
800 + //
801 + CWixInternalUIBootstrapperApplication(
802 + __in HMODULE hModule,
803 + __in_opt PREQBA_DATA* pPrereqData,
804 + __in IBootstrapperEngine* pEngine
805 + ) : CBalBaseBootstrapperApplication(pEngine, 3, 3000)
806 + {
807 + m_hModule = hModule;
808 + m_command = { };
809 + m_createArgs = { };
810 +
811 + m_plannedAction = BOOTSTRAPPER_ACTION_UNKNOWN;
812 +
813 + m_Bundle = { };
814 + m_Conditions = { };
815 + m_sczConfirmCloseMessage = NULL;
816 + m_sczFailedMessage = NULL;
817 +
818 + m_hUiThread = NULL;
819 + m_fRegistered = FALSE;
820 + m_hWnd = NULL;
821 +
822 + m_hrFinal = S_OK;
823 +
824 + m_restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE;
825 +
826 + m_fApplying = FALSE;
827 + m_fApplied = FALSE;
828 + m_fAutomaticRemoval = FALSE;
829 + m_fFailedToLoadPackage = FALSE;
830 + m_pPrereqData = pPrereqData;
831 +
832 + pEngine->AddRef();
833 + m_pEngine = pEngine;
834 + }
835 +
836 +
837 + //
838 + // Destructor - release member variables.
839 + //
840 + ~CWixInternalUIBootstrapperApplication()
841 + {
842 + ReleaseStr(m_sczFailedMessage);
843 + ReleaseStr(m_sczConfirmCloseMessage);
844 + BalConditionsUninitialize(&m_Conditions);
845 + BalInfoUninitialize(&m_Bundle);
846 +
847 + ReleaseNullObject(m_pEngine);
848 + }
849 +
850 +private:
851 + HMODULE m_hModule;
852 + BOOTSTRAPPER_CREATE_ARGS m_createArgs;
853 + BOOTSTRAPPER_COMMAND m_command;
854 + IBootstrapperEngine* m_pEngine;
855 + BOOTSTRAPPER_ACTION m_plannedAction;
856 +
857 + BAL_INFO_BUNDLE m_Bundle;
858 + BAL_CONDITIONS m_Conditions;
859 + LPWSTR m_sczFailedMessage;
860 + LPWSTR m_sczConfirmCloseMessage;
861 +
862 + HANDLE m_hUiThread;
863 + BOOL m_fRegistered;
864 + HWND m_hWnd;
865 +
866 + HRESULT m_hrFinal;
867 +
868 + BOOTSTRAPPER_APPLY_RESTART m_restartResult;
869 +
870 + BOOL m_fApplying;
871 + BOOL m_fApplied;
872 + BOOL m_fAutomaticRemoval;
873 + BOOL m_fFailedToLoadPackage;
874 + PREQBA_DATA* m_pPrereqData;
875 +};
876 +
877 +
878 +//
879 +// CreateBootstrapperApplication - creates a new IBootstrapperApplication object.
880 +//
881 +HRESULT CreateBootstrapperApplication(
882 + __in HMODULE hModule,
883 + __in_opt PREQBA_DATA* pPrereqData,
884 + __in IBootstrapperEngine* pEngine,
885 + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
886 + __inout BOOTSTRAPPER_CREATE_RESULTS* pResults,
887 + __out IBootstrapperApplication** ppApplication
888 + )
889 +{
890 + HRESULT hr = S_OK;
891 + CWixInternalUIBootstrapperApplication* pApplication = NULL;
892 +
893 + pApplication = new CWixInternalUIBootstrapperApplication(hModule, pPrereqData, pEngine);
894 + BalExitOnNull(pApplication, hr, E_OUTOFMEMORY, "Failed to create new InternalUI bootstrapper application object.");
895 +
896 + hr = pApplication->Initialize(pArgs);
897 + ExitOnFailure(hr, "CWixInternalUIBootstrapperApplication initialization failed.");
898 +
899 + pResults->pfnBootstrapperApplicationProc = BalBaseBootstrapperApplicationProc;
900 + pResults->pvBootstrapperApplicationProcContext = pApplication;
901 + *ppApplication = pApplication;
902 + pApplication = NULL;
903 +
904 +LExit:
905 + ReleaseObject(pApplication);
906 + return hr;
907 +}
908 +
909 +
910 +void DestroyBootstrapperApplication(
911 + __in IBootstrapperApplication* pApplication,
912 + __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
913 + __inout BOOTSTRAPPER_DESTROY_RESULTS* pResults
914 + )
915 +{
916 + CWixInternalUIBootstrapperApplication* pBA = (CWixInternalUIBootstrapperApplication*)pApplication;
917 + pBA->Uninitialize(pArgs, pResults);
918 +}
src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.h new
+18
@@ -0,0 +1,18 @@
1 +#pragma once
2 +// 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.
3 +
4 +
5 +HRESULT CreateBootstrapperApplication(
6 + __in HMODULE hModule,
7 + __in_opt PREQBA_DATA* pPrereqData,
8 + __in IBootstrapperEngine* pEngine,
9 + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
10 + __inout BOOTSTRAPPER_CREATE_RESULTS* pResults,
11 + __out IBootstrapperApplication** ppApplication
12 + );
13 +
14 +void DestroyBootstrapperApplication(
15 + __in IBootstrapperApplication* pApplication,
16 + __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
17 + __inout BOOTSTRAPPER_DESTROY_RESULTS* pResults
18 + );
src/ext/Bal/wixiuiba/precomp.cpp new
+3
@@ -0,0 +1,3 @@
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 "precomp.h"
src/ext/Bal/wixiuiba/precomp.h new
+30
@@ -0,0 +1,30 @@
1 +#pragma once
2 +// 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.
3 +
4 +
5 +#include <windows.h>
6 +#include <msiquery.h>
7 +
8 +#include <dutil.h>
9 +#include <dictutil.h>
10 +#include <locutil.h>
11 +#include <osutil.h>
12 +#include <pathutil.h>
13 +#include <procutil.h>
14 +#include <regutil.h>
15 +#include <strutil.h>
16 +#include <xmlutil.h>
17 +
18 +#include <BootstrapperEngine.h>
19 +#include <BootstrapperApplication.h>
20 +#include <IBootstrapperEngine.h>
21 +#include <IBootstrapperApplication.h>
22 +
23 +#include <balutil.h>
24 +#include <balinfo.h>
25 +#include <balcondition.h>
26 +
27 +#include <preqba.h>
28 +
29 +#include "WixInternalUIBootstrapperApplication.h"
30 +#include "wixiuiba.h"
src/ext/Bal/wixiuiba/wixiuiba.cpp new
+192
@@ -0,0 +1,192 @@
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 "precomp.h"
4 +
5 +static INTERNAL_UI_BA_STATE vstate = { };
6 +
7 +
8 +// internal function declarations
9 +
10 +static HRESULT LoadModulePaths(
11 + __in INTERNAL_UI_BA_STATE* pState
12 + );
13 +static HRESULT LoadInternalUIBAConfiguration(
14 + __in INTERNAL_UI_BA_STATE* pState,
15 + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs
16 + );
17 +static HRESULT CreatePrerequisiteBA(
18 + __in INTERNAL_UI_BA_STATE* pState,
19 + __in IBootstrapperEngine* pEngine,
20 + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
21 + __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
22 + );
23 +
24 +
25 +// function definitions
26 +
27 +extern "C" BOOL WINAPI DllMain(
28 + __in HINSTANCE hInstance,
29 + __in DWORD dwReason,
30 + __in LPVOID /*pvReserved*/
31 + )
32 +{
33 + switch (dwReason)
34 + {
35 + case DLL_PROCESS_ATTACH:
36 + ::DisableThreadLibraryCalls(hInstance);
37 + vstate.hInstance = hInstance;
38 + break;
39 +
40 + case DLL_PROCESS_DETACH:
41 + vstate.hInstance = NULL;
42 + break;
43 + }
44 +
45 + return TRUE;
46 +}
47 +
48 +// Note: This function assumes that COM was already initialized on the thread.
49 +extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
50 + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
51 + __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
52 + )
53 +{
54 + HRESULT hr = S_OK;
55 + IBootstrapperEngine* pEngine = NULL;
56 +
57 + hr = BalInitializeFromCreateArgs(pArgs, &pEngine);
58 + ExitOnFailure(hr, "Failed to initialize Bal.");
59 +
60 + if (!vstate.fInitialized)
61 + {
62 + hr = XmlInitialize();
63 + BalExitOnFailure(hr, "Failed to initialize XML.");
64 +
65 + hr = LoadModulePaths(&vstate);
66 + BalExitOnFailure(hr, "Failed to load the module paths.");
67 +
68 + hr = LoadInternalUIBAConfiguration(&vstate, pArgs);
69 + BalExitOnFailure(hr, "Failed to get the InternalUIBA configuration.");
70 +
71 + vstate.fInitialized = TRUE;
72 + }
73 +
74 + if (vstate.prereqData.fAlwaysInstallPrereqs && !vstate.prereqData.fCompleted ||
75 + FAILED(vstate.prereqData.hrFatalError))
76 + {
77 + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application.");
78 +
79 + hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults);
80 + BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
81 + }
82 + else
83 + {
84 + hr = CreateBootstrapperApplication(vstate.hInstance, &vstate.prereqData, pEngine, pArgs, pResults, &vstate.pApplication);
85 + BalExitOnFailure(hr, "Failed to create bootstrapper application interface.");
86 + }
87 +
88 +LExit:
89 + ReleaseNullObject(pEngine);
90 +
91 + return hr;
92 +}
93 +
94 +extern "C" void WINAPI BootstrapperApplicationDestroy(
95 + __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
96 + __in BOOTSTRAPPER_DESTROY_RESULTS* pResults
97 + )
98 +{
99 + BOOTSTRAPPER_DESTROY_RESULTS childResults = { };
100 +
101 + if (vstate.hPrereqModule)
102 + {
103 + PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vstate.hPrereqModule, "PrereqBootstrapperApplicationDestroy"));
104 + if (pfnDestroy)
105 + {
106 + (*pfnDestroy)(pArgs, &childResults);
107 + }
108 +
109 + ::FreeLibrary(vstate.hPrereqModule);
110 + vstate.hPrereqModule = NULL;
111 + }
112 +
113 + if (vstate.pApplication)
114 + {
115 + DestroyBootstrapperApplication(vstate.pApplication, pArgs, pResults);
116 + ReleaseNullObject(vstate.pApplication);
117 + }
118 +
119 + BalUninitialize();
120 +
121 + // Need to keep track of state between reloads.
122 + pResults->fDisableUnloading = TRUE;
123 +}
124 +
125 +static HRESULT LoadModulePaths(
126 + __in INTERNAL_UI_BA_STATE* pState
127 + )
128 +{
129 + HRESULT hr = S_OK;
130 + LPWSTR sczFullPath = NULL;
131 +
132 + hr = PathForCurrentProcess(&sczFullPath, pState->hInstance);
133 + ExitOnFailure(hr, "Failed to get the full host path.");
134 +
135 + hr = PathGetDirectory(sczFullPath, &pState->sczAppBase);
136 + ExitOnFailure(hr, "Failed to get the directory of the full process path.");
137 +
138 +LExit:
139 + ReleaseStr(sczFullPath);
140 +
141 + return hr;
142 +}
143 +
144 +static HRESULT LoadInternalUIBAConfiguration(
145 + __in INTERNAL_UI_BA_STATE* pState,
146 + __in const BOOTSTRAPPER_CREATE_ARGS* /*pArgs*/
147 + )
148 +{
149 + HRESULT hr = S_OK;
150 +
151 + pState->prereqData.fAlwaysInstallPrereqs = TRUE;
152 + pState->prereqData.fPerformHelp = TRUE;
153 + pState->prereqData.fPerformLayout = TRUE;
154 +
155 + return hr;
156 +}
157 +
158 +static HRESULT CreatePrerequisiteBA(
159 + __in INTERNAL_UI_BA_STATE* pState,
160 + __in IBootstrapperEngine* pEngine,
161 + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
162 + __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
163 + )
164 +{
165 + HRESULT hr = S_OK;
166 + LPWSTR sczPrereqPath = NULL;
167 + HMODULE hModule = NULL;
168 +
169 + hr = PathConcat(pState->sczAppBase, L"prereqba.dll", &sczPrereqPath);
170 + BalExitOnFailure(hr, "Failed to get path to pre-requisite BA.");
171 +
172 + hModule = ::LoadLibraryExW(sczPrereqPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
173 + ExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL.");
174 +
175 + PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_PREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "PrereqBootstrapperApplicationCreate"));
176 + ExitOnNullWithLastError(pfnCreate, hr, "Failed to get PrereqBootstrapperApplicationCreate entry-point from: %ls", sczPrereqPath);
177 +
178 + hr = pfnCreate(&pState->prereqData, pEngine, pArgs, pResults);
179 + ExitOnFailure(hr, "Failed to create prequisite bootstrapper app.");
180 +
181 + pState->hPrereqModule = hModule;
182 + hModule = NULL;
183 +
184 +LExit:
185 + if (hModule)
186 + {
187 + ::FreeLibrary(hModule);
188 + }
189 + ReleaseStr(sczPrereqPath);
190 +
191 + return hr;
192 +}
src/ext/Bal/wixiuiba/wixiuiba.def new
+6
@@ -0,0 +1,6 @@
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 +EXPORTS
5 + BootstrapperApplicationCreate
6 + BootstrapperApplicationDestroy
src/ext/Bal/wixiuiba/wixiuiba.h new
+13
@@ -0,0 +1,13 @@
1 +#pragma once
2 +// 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.
3 +
4 +
5 +struct INTERNAL_UI_BA_STATE
6 +{
7 + BOOL fInitialized;
8 + HINSTANCE hInstance;
9 + LPWSTR sczAppBase;
10 + HMODULE hPrereqModule;
11 + PREQBA_DATA prereqData;
12 + IBootstrapperApplication* pApplication;
13 +};
src/ext/Bal/wixiuiba/wixiuiba.vcxproj new
+72
@@ -0,0 +1,72 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<!-- 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. -->
3 +
4 +<Project DefaultTargets="Build" Toolsxmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 + <ItemGroup Label="ProjectConfigurations">
6 + <ProjectConfiguration Include="Debug|ARM64">
7 + <Configuration>Debug</Configuration>
8 + <Platform>ARM64</Platform>
9 + </ProjectConfiguration>
10 + <ProjectConfiguration Include="Release|ARM64">
11 + <Configuration>Release</Configuration>
12 + <Platform>ARM64</Platform>
13 + </ProjectConfiguration>
14 + <ProjectConfiguration Include="Debug|Win32">
15 + <Configuration>Debug</Configuration>
16 + <Platform>Win32</Platform>
17 + </ProjectConfiguration>
18 + <ProjectConfiguration Include="Release|Win32">
19 + <Configuration>Release</Configuration>
20 + <Platform>Win32</Platform>
21 + </ProjectConfiguration>
22 + <ProjectConfiguration Include="Debug|x64">
23 + <Configuration>Debug</Configuration>
24 + <Platform>x64</Platform>
25 + </ProjectConfiguration>
26 + <ProjectConfiguration Include="Release|x64">
27 + <Configuration>Release</Configuration>
28 + <Platform>x64</Platform>
29 + </ProjectConfiguration>
30 + </ItemGroup>
31 +
32 + <PropertyGroup Label="Globals">
33 + <ProjectGuid>{0F73E566-925C-448D-99CB-3A7F5DF399C8}</ProjectGuid>
34 + <ConfigurationType>DynamicLibrary</ConfigurationType>
35 + <CharacterSet>Unicode</CharacterSet>
36 + <TargetName>wixiuiba</TargetName>
37 + <ProjectModuleDefinitionFile>wixiuiba.def</ProjectModuleDefinitionFile>
38 + </PropertyGroup>
39 +
40 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
41 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
42 +
43 + <PropertyGroup>
44 + <ProjectAdditionalIncludeDirectories>..\wixstdba\inc</ProjectAdditionalIncludeDirectories>
45 + <ProjectAdditionalLinkLibraries>shlwapi.lib</ProjectAdditionalLinkLibraries>
46 + </PropertyGroup>
47 +
48 + <ItemGroup>
49 + <ClCompile Include="precomp.cpp">
50 + <PrecompiledHeader>Create</PrecompiledHeader>
51 + </ClCompile>
52 + <ClCompile Include="WixInternalUIBootstrapperApplication.cpp" />
53 + <ClCompile Include="wixiuiba.cpp" />
54 + </ItemGroup>
55 + <ItemGroup>
56 + <ClInclude Include="precomp.h" />
57 + <ClInclude Include="WixInternalUIBootstrapperApplication.h" />
58 + <ClInclude Include="wixiuiba.h" />
59 + </ItemGroup>
60 + <ItemGroup>
61 + <None Include="wixiuiba.def" />
62 + </ItemGroup>
63 +
64 + <ItemGroup>
65 + <PackageReference Include="WixToolset.BalUtil" />
66 +
67 + <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
68 + <PackageReference Include="GitInfo" PrivateAssets="All" />
69 + </ItemGroup>
70 +
71 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
72 +</Project>
src/ext/Bal/wixlib/BalExtension_platform.wxi
+14
@@ -18,6 +18,20 @@
18 <BootstrapperApplicationRef Id="WixDotNetCoreBootstrapperApplicationHost$(var.Suffix)" />
19 </Fragment>
20
21 + <Fragment>
22 + <BootstrapperApplication Id="WixInternalUIBootstrapperApplication$(var.Suffix)">
23 + <BootstrapperApplicationDll Id="WixInternalUIBootstrapperApplication" SourceFile="!(bindpath.$(var.platform))\wixiuiba.dll" />
24 + <Payload SourceFile="!(bindpath.$(var.platform))\wixstdba.dll" Name="prereqba.dll" />
25 + </BootstrapperApplication>
26 + </Fragment>
27 +
28 + <Fragment>
29 + <BootstrapperApplication Id="WixInternalUIBootstrapperApplication.Standard$(var.Suffix)">
30 + <PayloadGroupRef Id="WixIuibaStandardPayloads" />
31 + </BootstrapperApplication>
32 + <BootstrapperApplicationRef Id="WixInternalUIBootstrapperApplication$(var.Suffix)" />
33 + </Fragment>
34 +
35 <Fragment>
36 <BootstrapperApplication Id="WixStandardBootstrapperApplication$(var.Suffix)">
37 <BootstrapperApplicationDll Id="WixStandardBootstrapperApplication" SourceFile="!(bindpath.$(var.platform))\wixstdba.dll" />
src/ext/Bal/wixlib/bal.wixproj
+3
@@ -22,6 +22,9 @@
22 <ProjectReference Include="..\mbahost\mbahost.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" />
23 <ProjectReference Include="..\mbahost\mbahost.vcxproj" Properties="Platform=x64" ReferenceOutputAssembly="false" />
24 <ProjectReference Include="..\mbahost\mbahost.vcxproj" Properties="Platform=ARM64" ReferenceOutputAssembly="false" />
25 + <ProjectReference Include="..\wixiuiba\wixiuiba.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" />
26 + <ProjectReference Include="..\wixiuiba\wixiuiba.vcxproj" Properties="Platform=x64" ReferenceOutputAssembly="false" />
27 + <ProjectReference Include="..\wixiuiba\wixiuiba.vcxproj" Properties="Platform=ARM64" ReferenceOutputAssembly="false" />
28 <ProjectReference Include="..\wixstdba\wixstdba.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" />
29 <ProjectReference Include="..\wixstdba\wixstdba.vcxproj" Properties="Platform=x64" ReferenceOutputAssembly="false" />
30 <ProjectReference Include="..\wixstdba\wixstdba.vcxproj" Properties="Platform=ARM64" ReferenceOutputAssembly="false" />
src/ext/Bal/wixlib/wixiuiba.wxs new
+12
@@ -0,0 +1,12 @@
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 + <Fragment>
6 + <PayloadGroup Id="WixIuibaStandardPayloads">
7 + <Payload Name="mbapreq.thm" SourceFile="!(wix.WixIuibaThemeXml=SourceDir\iuipreq.thm)" />
8 + <Payload Name="mbapreq.png" SourceFile="!(wix.WixIuibaLogo=SourceDir\mbapreq.png)" />
9 + <Payload Name="mbapreq.wxl" SourceFile="!(wix.WixIuibaThemeWxl=SourceDir\iuipreq.wxl)" />
10 + </PayloadGroup>
11 + </Fragment>
12 +</Wix>
src/ext/Bal/wixstdba/Resources/iuipreq.thm new
+67
@@ -0,0 +1,67 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
3 + <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
4 + <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
5 + <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
6 + <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7 +
8 + <Window Width="485" Height="300" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
9 + <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="mbapreq.png" Visible="yes"/>
10 + <Label X="80" Y="11" Width="-11" Height="96" FontId="1" Visible="yes" DisablePrefix="yes">
11 + <Text>#(loc.Title)</Text>
12 + <Text Condition="WixBundleAction = 2 OR WixBundleCommandLineAction = 1">#(loc.NonPrereqTitle)</Text>
13 + </Label>
14 +
15 + <Page Name="Help">
16 + <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
17 + <Label X="11" Y="153" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
18 + <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
19 + <Text>#(loc.HelpCloseButton)</Text>
20 + <CloseWindowAction />
21 + </Button>
22 + </Page>
23 + <Page Name="Install">
24 + <Hypertext Name="EulaHyperlink" X="11" Y="121" Width="-11" Height="34" TabStop="yes" FontId="3">#(loc.InstallLicenseTerms)</Hypertext>
25 + <Button Name="InstallButton" X="-91" Y="-11" Width="130" Height="23" TabStop="yes" FontId="0">#(loc.InstallAcceptAndInstallButton)</Button>
26 + <Button Name="InstallDeclineButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
27 + <Text>#(loc.InstallDeclineButton)</Text>
28 + <CloseWindowAction />
29 + </Button>
30 + </Page>
31 + <Page Name="Progress">
32 + <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
33 + <Label X="11" Y="153" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
34 + <Label Name="OverallProgressPackageText" X="85" Y="153" Width="-11" Height="17" FontId="3" DisablePrefix="yes">[ProgressPackageName]</Label>
35 + <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="175" Width="-11" Height="15" />
36 + <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
37 + </Page>
38 + <Page Name="Success">
39 + <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
40 + <Text>#(loc.SuccessHeader)</Text>
41 + <Text Condition="WixBundleAction = 2">#(loc.SuccessLayoutHeader)</Text>
42 + </Label>
43 + <Label X="-11" Y="-20" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">
44 + <Text>#(loc.SuccessRestartText)</Text>
45 + </Label>
46 + <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
47 + <Button Name="SuccessCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
48 + <Text>#(loc.SuccessCloseButton)</Text>
49 + <CloseWindowAction />
50 + </Button>
51 + </Page>
52 + <Page Name="Failure">
53 + <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
54 + <Text>#(loc.FailureHeader)</Text>
55 + <Text Condition="WixBundleAction = 2">#(loc.FailureLayoutHeader)</Text>
56 + </Label>
57 + <Hypertext Name="FailureLogFileLink" X="11" Y="153" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureLogLinkText)</Hypertext>
58 + <Hypertext Name="FailureMessageText" X="22" Y="190" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes"/>
59 + <Label X="-11" Y="-20" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
60 + <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
61 + <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
62 + <Text>#(loc.FailureCloseButton)</Text>
63 + <CloseWindowAction />
64 + </Button>
65 + </Page>
66 + </Window>
67 +</Theme>
src/ext/Bal/wixstdba/Resources/iuipreq.wxl new
+34
@@ -0,0 +1,34 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<!-- 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. -->
3 +
4 +
5 +<WixLocalization Culture="en-us" Language="1033" xmlns="http://wixtoolset.org/schemas/v4/wxl">
6 + <String Id="Caption">[WixBundleName] Prerequisite Setup</String>
7 + <String Id="Title">Prerequisite required for [WixBundleName] setup</String>
8 + <String Id="NonPrereqTitle">[WixBundleName] setup</String>
9 + <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
10 + <String Id="HelpHeader">Setup Help</String>
11 + <String Id="HelpText">/passive | /quiet - displays minimal UI with no prompts or displays no UI and
12 + no prompts. By default UI and all prompts are displayed.
13 +
14 +/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.</String>
15 + <String Id="HelpCloseButton">&amp;Close</String>
16 + <String Id="InstallLicenseTerms">Click the "Accept and Install" button to accept the prerequisite &lt;a href="#"&gt;license terms&lt;/a&gt;.</String>
17 + <String Id="InstallAcceptAndInstallButton">&amp;Accept and Install</String>
18 + <String Id="InstallDeclineButton">&amp;Decline</String>
19 + <String Id="ProgressHeader">Setup Progress</String>
20 + <String Id="ProgressLabel">Processing:</String>
21 + <String Id="ProgressCancelButton">&amp;Cancel</String>
22 + <String Id="SuccessHeader">Prerequisite Setup Successful</String>
23 + <String Id="SuccessLayoutHeader">Layout Successfully Completed</String>
24 + <String Id="SuccessRestartText">You must restart your computer before [WixBundleName] setup can continue.</String>
25 + <String Id="SuccessRestartButton">&amp;Restart</String>
26 + <String Id="SuccessCloseButton">&amp;Close</String>
27 + <String Id="FailureHeader">Setup Failed</String>
28 + <String Id="FailureLayoutHeader">Layout Failed</String>
29 + <String Id="FailureLogLinkText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the &lt;a href="#"&gt;log file&lt;/a&gt;.</String>
30 + <String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
31 + <String Id="FailureRestartButton">&amp;Restart</String>
32 + <String Id="FailureCloseButton">&amp;Close</String>
33 + <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
34 +</WixLocalization>
src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+27 -14
@@ -248,10 +248,20 @@ public: // IBootstrapperApplication
248
249 if (m_fPrereq)
250 {
251 - // Pre-req BA should only show help or do an install (to launch the Managed BA which can then do the right action).
252 - if (BOOTSTRAPPER_ACTION_HELP != m_command.action)
251 + if (m_pPrereqData->fPerformLayout && BOOTSTRAPPER_ACTION_LAYOUT == m_command.action)
252 {
254 - m_command.action = BOOTSTRAPPER_ACTION_INSTALL;
253 + // The parent BA has requested that this BA be in charge of layout.
254 + m_fPrereq = FALSE;
255 + }
256 + else
257 + {
258 + m_fPreplanPrereqs = m_pPrereqData->fAlwaysInstallPrereqs;
259 +
260 + // Pre-req BA should only show help or do an install (to launch the parent BA which can then do the right action).
261 + if (BOOTSTRAPPER_ACTION_HELP != m_command.action)
262 + {
263 + m_command.action = BOOTSTRAPPER_ACTION_INSTALL;
264 + }
265 }
266 }
267 else // maybe modify the action state if the bundle is or is not already installed.
@@ -527,11 +537,11 @@ public: // IBootstrapperApplication
537 )
538 {
539 HRESULT hr = S_OK;
530 - BOOL fPlannedPrereqs = WIXSTDBA_STATE_PLANNING_PREREQS == m_state;
540 + BOOL fPreplannedPrereqs = WIXSTDBA_STATE_PLANNING_PREREQS == m_state;
541 WIXSTDBA_STATE completedState = WIXSTDBA_STATE_PLANNED;
542 BOOL fApply = TRUE;
543
534 - if (fPlannedPrereqs)
544 + if (fPreplannedPrereqs)
545 {
546 if (SUCCEEDED(hrStatus) && !m_fPrereqPackagePlanned)
547 {
@@ -547,7 +557,7 @@ public: // IBootstrapperApplication
557 // Need to force the state change since normally moving backwards is prevented.
558 ::PostMessageW(m_hWnd, WM_WIXSTDBA_CHANGE_STATE, 0, WIXSTDBA_STATE_HELP);
559
550 - ::PostMessageW(m_hWnd, WM_WIXSTDBA_SHOW_HELP, 0, 0);
560 + ::PostMessageW(m_hWnd, WM_WIXSTDBA_SHOW_HELP, 0, 0);
561
562 ExitFunction();
563 }
@@ -562,7 +572,7 @@ public: // IBootstrapperApplication
572 ExitFunction();
573 }
574
565 - if (fPlannedPrereqs)
575 + if (fPreplannedPrereqs)
576 {
577 // If the UI should be visible, display it now and hide the splash screen
578 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
@@ -1056,13 +1066,14 @@ public: // IBootstrapperApplication
1066
1067 hr = __super::OnExecutePackageComplete(wzPackageId, hrStatus, restart, recommendation, pAction);
1068
1059 - BAL_INFO_PACKAGE* pPackage = NULL;
1060 - HRESULT hrPrereq = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
1061 - if (SUCCEEDED(hrPrereq))
1069 + if (m_fPrereq && BOOTSTRAPPER_APPLY_RESTART_NONE != restart)
1070 {
1071 + BAL_INFO_PACKAGE* pPackage = NULL;
1072 + HRESULT hrPrereq = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
1073 +
1074 // If the prerequisite required a restart (any restart) then do an immediate
1075 // restart to ensure that the bundle will get launched again post reboot.
1065 - if (m_fPrereq && pPackage->fPrereqPackage && BOOTSTRAPPER_APPLY_RESTART_NONE != restart)
1076 + if (SUCCEEDED(hrPrereq) && pPackage->fPrereqPackage)
1077 {
1078 *pAction = BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_RESTART;
1079 }
@@ -2283,7 +2294,7 @@ private:
2294 // Okay, we're ready for packages now.
2295 pThis->SetState(WIXSTDBA_STATE_INITIALIZED, hr);
2296
2286 - if (!pThis->m_fPreplanPrereqs && BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action)
2297 + if (pThis->m_fPerformHelp && BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action)
2298 {
2299 firstAction = WM_WIXSTDBA_SHOW_HELP;
2300 }
@@ -4246,7 +4257,7 @@ public:
4257 m_hWnd = NULL;
4258
4259 m_state = WIXSTDBA_STATE_INITIALIZING;
4249 - m_hrFinal = pPrereqData ? pPrereqData->hrHostInitialization : S_OK;
4260 + m_hrFinal = pPrereqData ? pPrereqData->hrFatalError : S_OK;
4261
4262 m_restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE;
4263 m_fRestartRequired = FALSE;
@@ -4269,7 +4280,8 @@ public:
4280
4281 m_pPrereqData = pPrereqData;
4282 m_fPrereq = NULL != pPrereqData;
4272 - m_fPreplanPrereqs = m_fPrereq && m_pPrereqData->fAlwaysInstallPrereqs;
4283 + m_fPreplanPrereqs = FALSE;
4284 + m_fPerformHelp = !m_fPrereq || m_pPrereqData->fPerformHelp;
4285 m_fPrereqPackagePlanned = FALSE;
4286 m_fPrereqInstalled = FALSE;
4287 m_fPrereqSkipped = FALSE;
@@ -4554,6 +4566,7 @@ private:
4566 PREQBA_DATA* m_pPrereqData;
4567 BOOL m_fPrereq;
4568 BOOL m_fPreplanPrereqs;
4569 + BOOL m_fPerformHelp;
4570 BOOL m_fPrereqPackagePlanned;
4571 BOOL m_fPrereqInstalled;
4572 BOOL m_fPrereqSkipped;
src/ext/Bal/wixstdba/inc/preqba.h
+3 -1
@@ -4,8 +4,10 @@
4
5 struct PREQBA_DATA
6 {
7 - HRESULT hrHostInitialization;
7 + HRESULT hrFatalError;
8 BOOL fAlwaysInstallPrereqs;
9 + BOOL fPerformHelp;
10 + BOOL fPerformLayout;
11 BOOL fCompleted;
12 };
13
src/test/burn/TestData/Templates/Bundle.wxs
+4
@@ -33,6 +33,10 @@
33 <BootstrapperApplication>
34 <bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" />
35 </BootstrapperApplication>
36 + <?elseif $(var.BA) = "iui"?>
37 + <BootstrapperApplication>
38 + <bal:WixInternalUIBootstrapperApplication />
39 + </BootstrapperApplication>
40 <?else?>
41 <BootstrapperApplicationRef Id="$(var.BA)" />
42 <?endif?>
src/test/burn/TestData/TestData.proj
+1 -1
@@ -4,7 +4,7 @@
4 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup>
6 <TestDataProject Include="**\*.wixproj" />
7 -
7 +
8 <!-- https://github.com/wixtoolset/issues/issues/6401 -->
9 <TestDataProject Remove="DependencyTests\BundleC\BundleC.wixproj" />
10 <TestDataProject Remove="DependencyTests\BundleF_PatchAv1_0_1\BundleF_PatchAv1_0_1.wixproj" />
src/test/burn/TestData/WixIuiBaTests/ArchSpecificBundle/ArchSpecificBundle.wixproj new
+17
@@ -0,0 +1,17 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Bundle</OutputType>
5 + <BA>iui</BA>
6 + <UpgradeCode>{22B5ADAF-74D3-424A-8D32-9901FCF97E6D}</UpgradeCode>
7 + </PropertyGroup>
8 + <ItemGroup>
9 + <ProjectReference Include="..\InternalUIPackage\InternalUIPackage.wixproj" />
10 + <ProjectReference Include="..\InternalUIarm64Package\InternalUIarm64Package.wixproj" />
11 + <ProjectReference Include="..\InternalUIx64Package\InternalUIx64Package.wixproj" />
12 + <ProjectReference Include="..\InternalUIx86Package\InternalUIx86Package.wixproj" />
13 + </ItemGroup>
14 + <ItemGroup>
15 + <PackageReference Include="WixToolset.Bal.wixext" />
16 + </ItemGroup>
17 +</Project>
\ No newline at end of file
src/test/burn/TestData/WixIuiBaTests/ArchSpecificBundle/ArchSpecificBundle.wxs new
+13
@@ -0,0 +1,13 @@
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" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
5 + <Fragment>
6 + <PackageGroup Id="BundlePackages">
7 + <MsiPackage Id="InternalUIPackage" SourceFile="$(var.InternalUIPackage.TargetPath)" />
8 + <MsiPackage Id="InternalUIarm64Package" SourceFile="$(var.InternalUIarm64Package.TargetPath)" bal:PrimaryPackageType="arm64" />
9 + <MsiPackage Id="InternalUIx64Package" SourceFile="$(var.InternalUIx64Package.TargetPath)" bal:PrimaryPackageType="x64" />
10 + <MsiPackage Id="InternalUIx86Package" SourceFile="$(var.InternalUIx86Package.TargetPath)" bal:PrimaryPackageType="x86" />
11 + </PackageGroup>
12 + </Fragment>
13 +</Wix>
src/test/burn/TestData/WixIuiBaTests/ArchSpecificBundle/Bundle.wxs new
+63
@@ -0,0 +1,63 @@
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 +<?ifndef Version?>
4 +<?define Version = 1.0.0.0?>
5 +<?endif?>
6 +<?ifndef BundleLogDirectory?>
7 +<?define BundleLogDirectory = .?>
8 +<?endif?>
9 +
10 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
11 + <!-- The only difference from the template should be the SplashScreen and uncompressed -->
12 + <Bundle Name="~$(var.TestGroupName) - $(var.BundleName)" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)" Compressed="no" SplashScreenSourceFile="..\..\Manual\BafThmutilTesting\theme\star_transparent.bmp">
13 + <Log Prefix="$(var.BundleLogDirectory)\~$(var.TestGroupName)_$(var.BundleName)" />
14 +
15 + <Variable Name="TestGroupName" Value="$(var.TestGroupName)" />
16 +
17 + <?ifdef SoftwareTag?>
18 + <SoftwareTag Regid="regid.1995-08.com.example" InstallPath="[CommonAppDataFolder]regid.1995-08.com.example" />
19 + <?endif?>
20 +
21 + <?ifndef BA?>
22 + <!-- pulled in through the PackageGroupRef below -->
23 + <?elseif $(var.BA) = "TestBAdnc"?>
24 + <!-- pulled in through the PackageGroupRef below -->
25 + <?elseif $(var.BA) = "TestBA_x64"?>
26 + <!-- pulled in through the PackageGroupRef below -->
27 + <?elseif $(var.BA) = "TestBAdnc_x64"?>
28 + <!-- pulled in through the PackageGroupRef below -->
29 + <?elseif $(var.BA) = "WixBA"?>
30 + <!-- pulled in through the PackageGroupRef below -->
31 + <?elseif $(var.BA) = "WixBAdnc_x64"?>
32 + <!-- pulled in through the PackageGroupRef below -->
33 + <?elseif $(var.BA) = "hyperlinkLicense"?>
34 + <BootstrapperApplication>
35 + <bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" />
36 + </BootstrapperApplication>
37 + <?elseif $(var.BA) = "iui"?>
38 + <BootstrapperApplication>
39 + <bal:WixInternalUIBootstrapperApplication />
40 + </BootstrapperApplication>
41 + <?else?>
42 + <BootstrapperApplicationRef Id="$(var.BA)" />
43 + <?endif?>
44 +
45 + <Chain>
46 + <?ifndef BA?>
47 + <PackageGroupRef Id="TestBA" />
48 + <?elseif $(var.BA) = "TestBAdnc"?>
49 + <PackageGroupRef Id="TestBAdnc" />
50 + <?elseif $(var.BA) = "TestBA_x64"?>
51 + <PackageGroupRef Id="TestBA_x64" />
52 + <?elseif $(var.BA) = "TestBAdnc_x64"?>
53 + <PackageGroupRef Id="TestBAdnc_x64" />
54 + <?elseif $(var.BA) = "WixBA"?>
55 + <PackageGroupRef Id="WixBA" />
56 + <?elseif $(var.BA) = "WixBAdnc_x64"?>
57 + <PackageGroupRef Id="WixBAdnc_x64" />
58 + <?endif?>
59 +
60 + <PackageGroupRef Id="BundlePackages" />
61 + </Chain>
62 + </Bundle>
63 +</Wix>
src/test/burn/TestData/WixIuiBaTests/DtfSamples.sln renamed
+1 -1
@@ -5,7 +5,7 @@ VisualStudioVersion = 16.0.30114.105
5 MinimumVisualStudioVersion = 10.0.40219.1
6 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmbeddedUI", "EmbeddedUI\EmbeddedUI.csproj", "{864B8C50-7895-4485-AC89-900D86FD8C0D}"
7 EndProject
8 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleCA", "SampleCA\SampleCA.csproj", "{8F53B9CC-6FBE-493D-9C9A-09B2AD578CE7}"
8 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedCA", "ManagedCA\ManagedCA.csproj", "{8F53B9CC-6FBE-493D-9C9A-09B2AD578CE7}"
9 EndProject
10 Global
11 GlobalSection(SolutionConfigurationPlatforms) = preSolution
src/test/burn/TestData/WixIuiBaTests/EmbeddedUI/EmbeddedUI.config renamed
src/test/burn/TestData/WixIuiBaTests/EmbeddedUI/EmbeddedUI.csproj renamed
src/test/burn/TestData/WixIuiBaTests/EmbeddedUI/InstallProgressCounter.cs renamed
src/test/burn/TestData/WixIuiBaTests/EmbeddedUI/SampleEmbeddedUI.cs renamed
src/test/burn/TestData/WixIuiBaTests/EmbeddedUI/SetupWizard.xaml renamed
src/test/burn/TestData/WixIuiBaTests/EmbeddedUI/SetupWizard.xaml.cs renamed
src/test/burn/TestData/WixIuiBaTests/EmbeddedUIBundle/Bundle.wxs new
+63
@@ -0,0 +1,63 @@
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 +<?ifndef Version?>
4 +<?define Version = 1.0.0.0?>
5 +<?endif?>
6 +<?ifndef BundleLogDirectory?>
7 +<?define BundleLogDirectory = .?>
8 +<?endif?>
9 +
10 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
11 + <!-- The only difference from the template should be the SplashScreen and uncompressed -->
12 + <Bundle Name="~$(var.TestGroupName) - $(var.BundleName)" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)" Compressed="no" SplashScreenSourceFile="..\..\Manual\BafThmutilTesting\theme\star_transparent.bmp">
13 + <Log Prefix="$(var.BundleLogDirectory)\~$(var.TestGroupName)_$(var.BundleName)" />
14 +
15 + <Variable Name="TestGroupName" Value="$(var.TestGroupName)" />
16 +
17 + <?ifdef SoftwareTag?>
18 + <SoftwareTag Regid="regid.1995-08.com.example" InstallPath="[CommonAppDataFolder]regid.1995-08.com.example" />
19 + <?endif?>
20 +
21 + <?ifndef BA?>
22 + <!-- pulled in through the PackageGroupRef below -->
23 + <?elseif $(var.BA) = "TestBAdnc"?>
24 + <!-- pulled in through the PackageGroupRef below -->
25 + <?elseif $(var.BA) = "TestBA_x64"?>
26 + <!-- pulled in through the PackageGroupRef below -->
27 + <?elseif $(var.BA) = "TestBAdnc_x64"?>
28 + <!-- pulled in through the PackageGroupRef below -->
29 + <?elseif $(var.BA) = "WixBA"?>
30 + <!-- pulled in through the PackageGroupRef below -->
31 + <?elseif $(var.BA) = "WixBAdnc_x64"?>
32 + <!-- pulled in through the PackageGroupRef below -->
33 + <?elseif $(var.BA) = "hyperlinkLicense"?>
34 + <BootstrapperApplication>
35 + <bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" />
36 + </BootstrapperApplication>
37 + <?elseif $(var.BA) = "iui"?>
38 + <BootstrapperApplication>
39 + <bal:WixInternalUIBootstrapperApplication />
40 + </BootstrapperApplication>
41 + <?else?>
42 + <BootstrapperApplicationRef Id="$(var.BA)" />
43 + <?endif?>
44 +
45 + <Chain>
46 + <?ifndef BA?>
47 + <PackageGroupRef Id="TestBA" />
48 + <?elseif $(var.BA) = "TestBAdnc"?>
49 + <PackageGroupRef Id="TestBAdnc" />
50 + <?elseif $(var.BA) = "TestBA_x64"?>
51 + <PackageGroupRef Id="TestBA_x64" />
52 + <?elseif $(var.BA) = "TestBAdnc_x64"?>
53 + <PackageGroupRef Id="TestBAdnc_x64" />
54 + <?elseif $(var.BA) = "WixBA"?>
55 + <PackageGroupRef Id="WixBA" />
56 + <?elseif $(var.BA) = "WixBAdnc_x64"?>
57 + <PackageGroupRef Id="WixBAdnc_x64" />
58 + <?endif?>
59 +
60 + <PackageGroupRef Id="BundlePackages" />
61 + </Chain>
62 + </Bundle>
63 +</Wix>
src/test/burn/TestData/WixIuiBaTests/EmbeddedUIBundle/EmbeddedUIBundle.wixproj new
+15
@@ -0,0 +1,15 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Bundle</OutputType>
5 + <BA>iui</BA>
6 + <UpgradeCode>{5115D6AC-A1FE-40C6-BEB3-BEBB39E61579}</UpgradeCode>
7 + </PropertyGroup>
8 + <ItemGroup>
9 + <ProjectReference Include="..\EmbeddedUIPackage\EmbeddedUIPackage.wixproj" />
10 + <ProjectReference Include="..\InternalUIPackage\InternalUIPackage.wixproj" />
11 + </ItemGroup>
12 + <ItemGroup>
13 + <PackageReference Include="WixToolset.Bal.wixext" />
14 + </ItemGroup>
15 +</Project>
\ No newline at end of file
src/test/burn/TestData/WixIuiBaTests/EmbeddedUIBundle/EmbeddedUIBundle.wxs new
+11
@@ -0,0 +1,11 @@
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 + <Fragment>
6 + <PackageGroup Id="BundlePackages">
7 + <MsiPackage Id="InternalUIPackage" SourceFile="$(var.InternalUIPackage.TargetPath)" Permanent="yes" />
8 + <MsiPackage Id="EmbeddedUIPackage" SourceFile="$(var.EmbeddedUIPackage.TargetPath)" />
9 + </PackageGroup>
10 + </Fragment>
11 +</Wix>
src/test/burn/TestData/WixIuiBaTests/EmbeddedUIPackage/EmbeddedUIPackage.wixproj new
+16
@@ -0,0 +1,16 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <ProductComponentsRef>true</ProductComponentsRef>
5 + <UpgradeCode>{A6826B6D-2F3F-456D-BABF-1B8CDCE3AE68}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <ProjectReference Include="..\EmbeddedUI\EmbeddedUI.csproj" />
12 + </ItemGroup>
13 + <ItemGroup>
14 + <PackageReference Include="WixToolset.UI.wixext" />
15 + </ItemGroup>
16 +</Project>
\ No newline at end of file
src/test/burn/TestData/WixIuiBaTests/EmbeddedUIPackage/EmbeddedUIPackage.wxs new
+13
@@ -0,0 +1,13 @@
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" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
4 + <Fragment>
5 + <ComponentGroup Id="ProductComponents" />
6 +
7 + <ui:WixUI Id="WixUI_Minimal" />
8 +
9 + <UI>
10 + <EmbeddedUI SourceFile="$(var.EmbeddedUI.TargetDir)$(var.EmbeddedUI.TargetName).CA.dll" />
11 + </UI>
12 + </Fragment>
13 +</Wix>
src/test/burn/TestData/WixIuiBaTests/InternalUIBundle/Bundle.wxs new
+63
@@ -0,0 +1,63 @@
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 +<?ifndef Version?>
4 +<?define Version = 1.0.0.0?>
5 +<?endif?>
6 +<?ifndef BundleLogDirectory?>
7 +<?define BundleLogDirectory = .?>
8 +<?endif?>
9 +
10 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
11 + <!-- The only difference from the template should be the SplashScreen and uncompressed -->
12 + <Bundle Name="~$(var.TestGroupName) - $(var.BundleName)" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)" Compressed="no" SplashScreenSourceFile="..\..\Manual\BafThmutilTesting\theme\star_transparent.bmp">
13 + <Log Prefix="$(var.BundleLogDirectory)\~$(var.TestGroupName)_$(var.BundleName)" />
14 +
15 + <Variable Name="TestGroupName" Value="$(var.TestGroupName)" />
16 +
17 + <?ifdef SoftwareTag?>
18 + <SoftwareTag Regid="regid.1995-08.com.example" InstallPath="[CommonAppDataFolder]regid.1995-08.com.example" />
19 + <?endif?>
20 +
21 + <?ifndef BA?>
22 + <!-- pulled in through the PackageGroupRef below -->
23 + <?elseif $(var.BA) = "TestBAdnc"?>
24 + <!-- pulled in through the PackageGroupRef below -->
25 + <?elseif $(var.BA) = "TestBA_x64"?>
26 + <!-- pulled in through the PackageGroupRef below -->
27 + <?elseif $(var.BA) = "TestBAdnc_x64"?>
28 + <!-- pulled in through the PackageGroupRef below -->
29 + <?elseif $(var.BA) = "WixBA"?>
30 + <!-- pulled in through the PackageGroupRef below -->
31 + <?elseif $(var.BA) = "WixBAdnc_x64"?>
32 + <!-- pulled in through the PackageGroupRef below -->
33 + <?elseif $(var.BA) = "hyperlinkLicense"?>
34 + <BootstrapperApplication>
35 + <bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" />
36 + </BootstrapperApplication>
37 + <?elseif $(var.BA) = "iui"?>
38 + <BootstrapperApplication>
39 + <bal:WixInternalUIBootstrapperApplication />
40 + </BootstrapperApplication>
41 + <?else?>
42 + <BootstrapperApplicationRef Id="$(var.BA)" />
43 + <?endif?>
44 +
45 + <Chain>
46 + <?ifndef BA?>
47 + <PackageGroupRef Id="TestBA" />
48 + <?elseif $(var.BA) = "TestBAdnc"?>
49 + <PackageGroupRef Id="TestBAdnc" />
50 + <?elseif $(var.BA) = "TestBA_x64"?>
51 + <PackageGroupRef Id="TestBA_x64" />
52 + <?elseif $(var.BA) = "TestBAdnc_x64"?>
53 + <PackageGroupRef Id="TestBAdnc_x64" />
54 + <?elseif $(var.BA) = "WixBA"?>
55 + <PackageGroupRef Id="WixBA" />
56 + <?elseif $(var.BA) = "WixBAdnc_x64"?>
57 + <PackageGroupRef Id="WixBAdnc_x64" />
58 + <?endif?>
59 +
60 + <PackageGroupRef Id="BundlePackages" />
61 + </Chain>
62 + </Bundle>
63 +</Wix>
src/test/burn/TestData/WixIuiBaTests/InternalUIBundle/InternalUIBundle.wixproj new
+14
@@ -0,0 +1,14 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Bundle</OutputType>
5 + <BA>iui</BA>
6 + <UpgradeCode>{62CB2BAE-129D-41D1-928B-5353FC542130}</UpgradeCode>
7 + </PropertyGroup>
8 + <ItemGroup>
9 + <ProjectReference Include="..\InternalUIPackage\InternalUIPackage.wixproj" />
10 + </ItemGroup>
11 + <ItemGroup>
12 + <PackageReference Include="WixToolset.Bal.wixext" />
13 + </ItemGroup>
14 +</Project>
\ No newline at end of file
src/test/burn/TestData/WixIuiBaTests/InternalUIBundle/InternalUIBundle.wxs new
+10
@@ -0,0 +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 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 + <Fragment>
6 + <PackageGroup Id="BundlePackages">
7 + <MsiPackage Id="InternalUIPackage" SourceFile="$(var.InternalUIPackage.TargetPath)" />
8 + </PackageGroup>
9 + </Fragment>
10 +</Wix>
src/test/burn/TestData/WixIuiBaTests/InternalUIPackage/InternalUIPackage.wixproj new
+16
@@ -0,0 +1,16 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <ProductComponentsRef>true</ProductComponentsRef>
5 + <UpgradeCode>{7A0FE267-9EAE-4780-B41E-60C9E7044F53}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <ProjectReference Include="..\ManagedCA\ManagedCA.csproj" />
12 + </ItemGroup>
13 + <ItemGroup>
14 + <PackageReference Include="WixToolset.UI.wixext" />
15 + </ItemGroup>
16 +</Project>
\ No newline at end of file
src/test/burn/TestData/WixIuiBaTests/InternalUIPackage/InternalUIPackage.wxs new
+24
@@ -0,0 +1,24 @@
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" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
4 + <Fragment>
5 + <ComponentGroup Id="ProductComponents" />
6 +
7 + <ui:WixUI Id="WixUI_Minimal" />
8 +
9 + <Binary Id="TestData" SourceFile="$(var.ManagedCA.TargetDir)testsub\testfile.txt" />
10 + <Binary Id="ManagedCA" SourceFile="$(var.ManagedCA.TargetDir)$(var.ManagedCA.TargetName).CA.dll" />
11 + <CustomAction Id="SampleCA1" BinaryRef="ManagedCA" DllEntry="SampleCA1" Execute="firstSequence" />
12 + <CustomAction Id="SampleCustomAction2" BinaryRef="ManagedCA" DllEntry="SampleCA2" Execute="firstSequence" Return="ignore" />
13 +
14 + <InstallUISequence>
15 + <Custom Action="SampleCA1" After="CostFinalize" Condition="NOT Installed" />
16 + <Custom Action="SampleCustomAction2" After="SampleCA1" Condition="NOT Installed" />
17 + </InstallUISequence>
18 +
19 + <InstallExecuteSequence>
20 + <Custom Action="SampleCA1" After="CostFinalize" Condition="NOT Installed" />
21 + <Custom Action="SampleCustomAction2" After="SampleCA1" Condition="NOT Installed" />
22 + </InstallExecuteSequence>
23 + </Fragment>
24 +</Wix>
src/test/burn/TestData/WixIuiBaTests/InternalUIarm64Package/InternalUIarm64Package.wixproj new
+14
@@ -0,0 +1,14 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <InstallerPlatform>arm64</InstallerPlatform>
5 + <ProductComponentsRef>true</ProductComponentsRef>
6 + <UpgradeCode>{357EBF93-039C-4378-8BCB-8B53F9B9F69A}</UpgradeCode>
7 + </PropertyGroup>
8 + <ItemGroup>
9 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
10 + </ItemGroup>
11 + <ItemGroup>
12 + <PackageReference Include="WixToolset.UI.wixext" />
13 + </ItemGroup>
14 +</Project>
\ No newline at end of file
src/test/burn/TestData/WixIuiBaTests/InternalUIarm64Package/InternalUIarm64Package.wxs new
+9
@@ -0,0 +1,9 @@
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" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
4 + <Fragment>
5 + <ComponentGroup Id="ProductComponents" />
6 +
7 + <ui:WixUI Id="WixUI_Minimal" />
8 + </Fragment>
9 +</Wix>
src/test/burn/TestData/WixIuiBaTests/InternalUIx64Package/InternalUIx64Package.wixproj new
+14
@@ -0,0 +1,14 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <InstallerPlatform>x64</InstallerPlatform>
5 + <ProductComponentsRef>true</ProductComponentsRef>
6 + <UpgradeCode>{2EBACF8F-BECD-401C-94F2-CFA2C9C3C07F}</UpgradeCode>
7 + </PropertyGroup>
8 + <ItemGroup>
9 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
10 + </ItemGroup>
11 + <ItemGroup>
12 + <PackageReference Include="WixToolset.UI.wixext" />
13 + </ItemGroup>
14 +</Project>
\ No newline at end of file
src/test/burn/TestData/WixIuiBaTests/InternalUIx64Package/InternalUIx64Package.wxs new
+9
@@ -0,0 +1,9 @@
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" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
4 + <Fragment>
5 + <ComponentGroup Id="ProductComponents" />
6 +
7 + <ui:WixUI Id="WixUI_Minimal" />
8 + </Fragment>
9 +</Wix>
src/test/burn/TestData/WixIuiBaTests/InternalUIx86Package/InternalUIx86Package.wixproj new
+14
@@ -0,0 +1,14 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <InstallerPlatform>x64</InstallerPlatform>
5 + <ProductComponentsRef>true</ProductComponentsRef>
6 + <UpgradeCode>{1FA46DA0-5F83-459A-8A30-3E5A54D20A4D}</UpgradeCode>
7 + </PropertyGroup>
8 + <ItemGroup>
9 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
10 + </ItemGroup>
11 + <ItemGroup>
12 + <PackageReference Include="WixToolset.UI.wixext" />
13 + </ItemGroup>
14 +</Project>
\ No newline at end of file
src/test/burn/TestData/WixIuiBaTests/InternalUIx86Package/InternalUIx86Package.wxs new
+9
@@ -0,0 +1,9 @@
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" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
4 + <Fragment>
5 + <ComponentGroup Id="ProductComponents" />
6 +
7 + <ui:WixUI Id="WixUI_Minimal" />
8 + </Fragment>
9 +</Wix>
src/test/burn/TestData/WixIuiBaTests/ManagedCA/CustomAction.config renamed
src/test/burn/TestData/WixIuiBaTests/ManagedCA/ManagedCA.csproj renamed
src/test/burn/TestData/WixIuiBaTests/ManagedCA/SampleCA.cs renamed
src/test/burn/TestData/WixIuiBaTests/ManagedCA/testsub/testfile.txt renamed
src/test/burn/WixTestTools/PackageVerifier.cs
+14 -4
@@ -63,17 +63,27 @@ namespace WixTestTools
63 return row.Value;
64 }
65
66 - public void VerifyInstalled(bool installed)
66 + public bool IsInstalled()
67 {
68 var productCode = this.GetProperty("ProductCode");
69 - Assert.Equal(installed, MsiUtilities.IsProductInstalled(productCode));
69 + return MsiUtilities.IsProductInstalled(productCode);
70 }
71
72 - public void VerifyInstalledWithVersion(bool installed)
72 + public bool IsInstalledWithVersion()
73 {
74 var productCode = this.GetProperty("ProductCode");
75 Version prodVersion = new Version(this.GetProperty("ProductVersion"));
76 - Assert.Equal(installed, MsiUtilities.IsProductInstalledWithVersion(productCode, prodVersion));
76 + return MsiUtilities.IsProductInstalledWithVersion(productCode, prodVersion);
77 + }
78 +
79 + public void VerifyInstalled(bool installed)
80 + {
81 + Assert.Equal(installed, this.IsInstalled());
82 + }
83 +
84 + public void VerifyInstalledWithVersion(bool installed)
85 + {
86 + Assert.Equal(installed, this.IsInstalledWithVersion());
87 }
88
89 public void DeleteTestRegistryValue(string name)
src/test/burn/WixToolsetTest.BurnE2E/WixIuiBaTests.cs new
+144
@@ -0,0 +1,144 @@
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.BurnE2E
4 +{
5 + using WixTestTools;
6 + using Xunit;
7 + using Xunit.Abstractions;
8 +
9 + public class WixIuiBaTests : BurnE2ETests
10 + {
11 + public WixIuiBaTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
12 +
13 + [RuntimeFact]
14 + public void CanInstallArchitectureSpecificPrimaryPackage()
15 + {
16 + var defaultPackage = this.CreatePackageInstaller("InternalUIPackage");
17 + var x86Package = this.CreatePackageInstaller("InternalUIx86Package");
18 + var x64Package = this.CreatePackageInstaller("InternalUIx64Package");
19 + var arm64Package = this.CreatePackageInstaller("InternalUIarm64Package");
20 + var bundle = this.CreateBundleInstaller("ArchSpecificBundle");
21 +
22 + defaultPackage.VerifyInstalled(false);
23 + x86Package.VerifyInstalled(false);
24 + x64Package.VerifyInstalled(false);
25 + arm64Package.VerifyInstalled(false);
26 + bundle.VerifyUnregisteredAndRemovedFromPackageCache();
27 +
28 + bundle.Install();
29 + bundle.VerifyRegisteredAndInPackageCache();
30 + defaultPackage.VerifyInstalled(false);
31 +
32 + var archSpecificInstalls = 0;
33 + if (x86Package.IsInstalled())
34 + {
35 + ++archSpecificInstalls;
36 + }
37 +
38 + if (x64Package.IsInstalled())
39 + {
40 + ++archSpecificInstalls;
41 + }
42 +
43 + if (arm64Package.IsInstalled())
44 + {
45 + ++archSpecificInstalls;
46 + }
47 +
48 + Assert.Equal(1, archSpecificInstalls);
49 +
50 + bundle.Uninstall();
51 + bundle.VerifyUnregisteredAndRemovedFromPackageCache();
52 + defaultPackage.VerifyInstalled(false);
53 + x86Package.VerifyInstalled(false);
54 + x64Package.VerifyInstalled(false);
55 + arm64Package.VerifyInstalled(false);
56 + }
57 +
58 + [RuntimeFact]
59 + public void CanSilentlyInstallAndUninstallEmbeddedUIBundle()
60 + {
61 + var prereqPackage = this.CreatePackageInstaller("InternalUIPackage");
62 + var package = this.CreatePackageInstaller("EmbeddedUIPackage");
63 + var bundle = this.CreateBundleInstaller("EmbeddedUIBundle");
64 +
65 + prereqPackage.VerifyInstalled(false);
66 + package.VerifyInstalled(false);
67 + bundle.VerifyUnregisteredAndRemovedFromPackageCache();
68 +
69 + bundle.Install();
70 + bundle.VerifyRegisteredAndInPackageCache();
71 + prereqPackage.VerifyInstalled(true);
72 + package.VerifyInstalled(true);
73 +
74 + bundle.Uninstall();
75 + bundle.VerifyUnregisteredAndRemovedFromPackageCache();
76 + prereqPackage.VerifyInstalled(true);
77 + package.VerifyInstalled(false);
78 + }
79 +
80 + [RuntimeFact]
81 + public void CanSilentlyInstallAndUninstallInternalUIBundle()
82 + {
83 + var package = this.CreatePackageInstaller("InternalUIPackage");
84 + var bundle = this.CreateBundleInstaller("InternalUIBundle");
85 +
86 + package.VerifyInstalled(false);
87 + bundle.VerifyUnregisteredAndRemovedFromPackageCache();
88 +
89 + bundle.Install();
90 + bundle.VerifyRegisteredAndInPackageCache();
91 + package.VerifyInstalled(true);
92 +
93 + bundle.Uninstall();
94 + bundle.VerifyUnregisteredAndRemovedFromPackageCache();
95 + package.VerifyInstalled(false);
96 + }
97 +
98 + // Manual test for EmbeddedUIBundle:
99 + // 1. Double click EmbeddedUIBundle.exe.
100 + // 2. Verify that the prereq BA came up and click the install button (allow elevation).
101 + // 3. Verify that the prereq BA automatically closed after installing the prereq.
102 + // 4. Verify that the MSI UI came up and click the install button.
103 + // 5. After it's finished, click the exit button.
104 + // 6. Verify that no other UI is shown and that everything was installed.
105 + // 7. Double click EmbeddedUIBundle.exe (allow elevation).
106 + // 8. Verify that the prereq BA did not come up.
107 + // 9. Verify that the MSI UI came up and click the uninstall button.
108 + // 10. After it's finished, click the exit button.
109 + // 11. Verify that no other UI is shown and that everything was uninstalled except for the prereq which was permanent.
110 + // 12. Uninstall InternalUIPackage to make sure the machine is clean for other tests.
111 +
112 + // Alternate EmbeddedUIBundle test - manually install InternalUIPackage first and verify that the prereq BA doesn't come up during install either.
113 +
114 + // Manual test for InternalUIBundle:
115 + // 1. Double click InternalUIBundle.exe on a machine that will prompt for elevation.
116 + // 2. Verify that the splash screen appeared but the prereq BA did not come up.
117 + // 3. Verify that the elevation prompt came up immediately instead of flashing on the taskbar. (This is currently broken)
118 + // 4. Allow elevation.
119 + // 5. Verify that the MSI UI came up and the splash screen disappeared.
120 + // 6. Accept the two CA messages and click the install button.
121 + // 7. After it's finished, click the exit button.
122 + // 8. Verify that no other UI is shown and that everything was installed.
123 + // 9. Double click InternalUIBundle.exe (allow elevation).
124 + // 10. Verify that the prereq BA did not come up.
125 + // 11. Verify that the MSI UI came up and click the uninstall button.
126 + // 12. After it's finished, click the exit button.
127 + // 13. Verify that no other UI is shown and that everything was uninstalled to make sure the machine is clean for other tests.
128 +
129 + // Manual test for Help:
130 + // 1. Run EmbeddedUIBundle.exe /help from the command line.
131 + // 2. Verify that the prereq BA shows the help information without trying to install the prereqs.
132 +
133 + // Manual test for Layout:
134 + // 1. Run EmbeddedUIBundle.exe /layout from an unelevated command line on a machine that will prompt for elevation.
135 + // 2. Verify that the prereq BA performs the layout without requiring any input from the user.
136 + // 3. Verify that it never prompted for elevation.
137 + // 4. Click the exit button.
138 +
139 + // Manual test for Caching error:
140 + // 1. Copy InternalUIBundle.exe to a separate folder so that it can't find InternalUIPackage.msi.
141 + // 2. Attempt to install InternalUIBundle.exe (allow elevation).
142 + // 3. Verify that the prereq BA comes up with the Failure page saying that a file couldn't be found.
143 + }
144 +}
src/test/dtf/Directory.Build.props deleted
-11
@@ -1,11 +0,0 @@
1 -<?xml version="1.0" encoding="utf-8"?>
2 -<!-- 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. -->
3 -<Project>
4 - <PropertyGroup>
5 - <SegmentName>IntegrationDtf</SegmentName>
6 - <SignOutput>false</SignOutput>
7 - </PropertyGroup>
8 -
9 - <Import Project="..\..\Directory.Build.props" />
10 - <Import Project="Directory$(MSBuildProjectExtension).props" Condition=" Exists('Directory$(MSBuildProjectExtension).props') " />
11 -</Project>
src/test/dtf/Directory.Build.targets deleted
-6
@@ -1,6 +0,0 @@
1 -<?xml version="1.0" encoding="utf-8"?>
2 -<!-- 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. -->
3 -<Project>
4 - <Import Project="..\..\Directory.Build.targets" />
5 - <Import Project="Directory$(MSBuildProjectExtension).targets" Condition=" Exists('Directory$(MSBuildProjectExtension).targets') " />
6 -</Project>
src/test/test.cmd
-2
@@ -14,8 +14,6 @@
14 @call msi\test_msi.cmd %_C% %_T% || exit /b
15 @call burn\test_burn.cmd %_C% %_T% || exit /b
16
17 -msbuild -Restore dtf\DtfE2ETests.sln -p:Configuration=%_C% -nologo -m -warnaserror -bl:%_L%\dtfe2etests.binlog || exit /b
18 -
17 dotnet test wix -c %_C% --nologo -l "trx;LogFileName=%_L%\TestResults\WixToolsetTest.WixE2ETests.trx" || exit /b
18
19 @popd
src/wix/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs
+3 -2
@@ -10,6 +10,7 @@ namespace WixToolset.Core.Burn.Bind
10 using WixToolset.Core.Burn.Bundles;
11 using WixToolset.Core.Burn.ExtensibilityServices;
12 using WixToolset.Data;
13 + using WixToolset.Data.Burn;
14 using WixToolset.Data.Symbols;
15 using WixToolset.Extensibility;
16 using WixToolset.Extensibility.Services;
@@ -191,10 +192,10 @@ namespace WixToolset.Core.Burn.Bind
192 switch (customDataSymbol.Type)
193 {
194 case WixBundleCustomDataType.BootstrapperApplication:
194 - writer.WriteStartElement(elementName, BurnCommon.BADataNamespace);
195 + writer.WriteStartElement(elementName, BurnConstants.BootstrapperApplicationDataNamespace);
196 break;
197 case WixBundleCustomDataType.BundleExtension:
197 - writer.WriteStartElement(elementName, BurnCommon.BundleExtensionDataNamespace);
198 + writer.WriteStartElement(elementName, BurnConstants.BundleExtensionDataNamespace);
199 break;
200 default:
201 throw new NotImplementedException();
src/wix/WixToolset.Core.Burn/Bundles/BurnCommon.cs
-2
@@ -24,10 +24,8 @@ namespace WixToolset.Core.Burn.Bundles
24 public const string BurnAuthoredContainerEmbeddedIdFormat = "a{0}";
25
26 public const string BADataFileName = "BootstrapperApplicationData.xml";
27 - public const string BADataNamespace = "http://wixtoolset.org/schemas/v4/BootstrapperApplicationData";
27
28 public const string BundleExtensionDataFileName = "BundleExtensionData.xml";
30 - public const string BundleExtensionDataNamespace = "http://wixtoolset.org/schemas/v4/BundleExtensionData";
29
30 // See WinNT.h for details about the PE format, including the
31 // structure and offsets for IMAGE_DOS_HEADER, IMAGE_NT_HEADERS32,
src/wix/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
+1 -1
@@ -67,7 +67,7 @@ namespace WixToolset.Core.Burn.Bundles
67 {
68 writer.Formatting = Formatting.Indented;
69 writer.WriteStartDocument();
70 - writer.WriteStartElement("BootstrapperApplicationData", BurnCommon.BADataNamespace);
70 + writer.WriteStartElement("BootstrapperApplicationData", BurnConstants.BootstrapperApplicationDataNamespace);
71
72 this.WriteBundleInfo(writer);
73
src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs
+1 -1
@@ -53,7 +53,7 @@ namespace WixToolset.Core.Burn.Bundles
53 {
54 writer.Formatting = Formatting.Indented;
55 writer.WriteStartDocument();
56 - writer.WriteStartElement("BundleExtensionData", BurnCommon.BundleExtensionDataNamespace);
56 + writer.WriteStartElement("BundleExtensionData", BurnConstants.BundleExtensionDataNamespace);
57
58 this.InternalBurnBackendHelper.WriteBundleExtensionData(writer);
59
src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs
+3 -2
@@ -9,6 +9,7 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
9 using System.Xml;
10 using WixToolset.Core.Burn.Bundles;
11 using WixToolset.Data;
12 + using WixToolset.Data.Burn;
13 using WixToolset.Data.Symbols;
14 using WixToolset.Data.WindowsInstaller.Rows;
15 using WixToolset.Extensibility.Data;
@@ -160,7 +161,7 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
161
162 public void AddBootstrapperApplicationData(IntermediateSymbol symbol, bool symbolIdIsIdAttribute = false)
163 {
163 - this.BootstrapperApplicationManifestData.AddSymbol(symbol, symbolIdIsIdAttribute, BurnCommon.BADataNamespace);
164 + this.BootstrapperApplicationManifestData.AddSymbol(symbol, symbolIdIsIdAttribute, BurnConstants.BootstrapperApplicationDataNamespace);
165 }
166
167 public void AddBundleExtensionData(string extensionId, string xml)
@@ -172,7 +173,7 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
173 public void AddBundleExtensionData(string extensionId, IntermediateSymbol symbol, bool symbolIdIsIdAttribute = false)
174 {
175 var manifestData = this.GetBundleExtensionManifestData(extensionId);
175 - manifestData.AddSymbol(symbol, symbolIdIsIdAttribute, BurnCommon.BundleExtensionDataNamespace);
176 + manifestData.AddSymbol(symbol, symbolIdIsIdAttribute, BurnConstants.BundleExtensionDataNamespace);
177 }
178
179 #endregion
src/wix/WixToolset.Core.TestPackage/BundleExtractor.cs
+3 -2
@@ -5,6 +5,7 @@ namespace WixToolset.Core.TestPackage
5 using System.IO;
6 using System.Xml;
7 using WixToolset.Core.Burn.Bundles;
8 + using WixToolset.Data.Burn;
9 using WixToolset.Extensibility.Services;
10
11 /// <summary>
@@ -72,7 +73,7 @@ namespace WixToolset.Core.TestPackage
73 public static XmlNamespaceManager GetBADataNamespaceManager(XmlDocument document, string prefix)
74 {
75 var namespaceManager = new XmlNamespaceManager(document.NameTable);
75 - namespaceManager.AddNamespace(prefix, BurnCommon.BADataNamespace);
76 + namespaceManager.AddNamespace(prefix, BurnConstants.BootstrapperApplicationDataNamespace);
77 return namespaceManager;
78 }
79
@@ -85,7 +86,7 @@ namespace WixToolset.Core.TestPackage
86 public static XmlNamespaceManager GetBundleExtensionDataNamespaceManager(XmlDocument document, string prefix)
87 {
88 var namespaceManager = new XmlNamespaceManager(document.NameTable);
88 - namespaceManager.AddNamespace(prefix, BurnCommon.BundleExtensionDataNamespace);
89 + namespaceManager.AddNamespace(prefix, BurnConstants.BundleExtensionDataNamespace);
90 return namespaceManager;
91 }
92