From 2a87b3e728fb56202d21d402cecc0bceeac49ade Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Sun, 19 Jul 2020 15:05:27 +1000 Subject: Generate the bundle's application manifest in the Burn backend. --- src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs | 2 +- .../Bundles/CreateBundleExeCommand.cs | 143 ++++++++++++++++++--- .../BundleFixture.cs | 14 ++ 3 files changed, 143 insertions(+), 16 deletions(-) diff --git a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index a64bdcc1..8522eb3e 100644 --- a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs +++ b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs @@ -475,7 +475,7 @@ namespace WixToolset.Core.Burn } { - var command = new CreateBundleExeCommand(this.Messaging, this.BackendHelper, this.IntermediateFolder, this.OutputPath, bundleSymbol, uxContainer, containers); + var command = new CreateBundleExeCommand(this.Messaging, this.BackendHelper, this.IntermediateFolder, this.OutputPath, bundleApplicationSymbol, bundleSymbol, uxContainer, containers); command.Execute(); fileTransfers.Add(command.Transfer); diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs index 3cf6e0aa..f804a2d8 100644 --- a/src/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs @@ -6,20 +6,24 @@ namespace WixToolset.Core.Burn.Bundles using System.Collections.Generic; using System.IO; using System.Reflection; + using System.Text; + using System.Xml; using WixToolset.Data; using WixToolset.Data.Burn; using WixToolset.Data.Symbols; + using WixToolset.Dtf.Resources; using WixToolset.Extensibility.Data; using WixToolset.Extensibility.Services; internal class CreateBundleExeCommand { - public CreateBundleExeCommand(IMessaging messaging, IBackendHelper backendHelper, string intermediateFolder, string outputPath, WixBundleSymbol bundleSymbol, WixBundleContainerSymbol uxContainer, IEnumerable containers) + public CreateBundleExeCommand(IMessaging messaging, IBackendHelper backendHelper, string intermediateFolder, string outputPath, WixBootstrapperApplicationSymbol bootstrapperApplicationSymbol, WixBundleSymbol bundleSymbol, WixBundleContainerSymbol uxContainer, IEnumerable containers) { this.Messaging = messaging; this.BackendHelper = backendHelper; this.IntermediateFolder = intermediateFolder; this.OutputPath = outputPath; + this.BootstrapperApplicationSymbol = bootstrapperApplicationSymbol; this.BundleSymbol = bundleSymbol; this.UXContainer = uxContainer; this.Containers = containers; @@ -35,6 +39,8 @@ namespace WixToolset.Core.Burn.Bundles private string OutputPath { get; } + private WixBootstrapperApplicationSymbol BootstrapperApplicationSymbol { get; } + private WixBundleSymbol BundleSymbol { get; } private WixBundleContainerSymbol UXContainer { get; } @@ -64,7 +70,11 @@ namespace WixToolset.Core.Burn.Bundles File.Copy(stubFile, bundleTempPath, true); File.SetAttributes(bundleTempPath, FileAttributes.Normal); - this.UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleSymbol); + var windowsAssemblyVersion = GetWindowsAssemblyVersion(this.BundleSymbol); + + var applicationManifestData = GenerateApplicationManifest(this.BundleSymbol, this.BootstrapperApplicationSymbol, this.OutputPath, windowsAssemblyVersion); + + UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleSymbol, windowsAssemblyVersion, applicationManifestData); // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers // if they should be attached. @@ -91,16 +101,105 @@ namespace WixToolset.Core.Burn.Bundles } } - private void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleSymbol bundleInfo) + private static byte[] GenerateApplicationManifest(WixBundleSymbol bundleSymbol, WixBootstrapperApplicationSymbol bootstrapperApplicationSymbol, string outputPath, Version windowsAssemblyVersion) { - var resources = new Dtf.Resources.ResourceCollection(); - var version = new Dtf.Resources.VersionResource("#1", 1033); + const string asmv1Namespace = "urn:schemas-microsoft-com:asm.v1"; + const string asmv3Namespace = "urn:schemas-microsoft-com:asm.v3"; + const string compatv1Namespace = "urn:schemas-microsoft-com:compatibility.v1"; + const string ws2005Namespace = "http://schemas.microsoft.com/SMI/2005/WindowsSettings"; + + var bundleFileName = Path.GetFileName(outputPath); + var bundleAssemblyVersion = windowsAssemblyVersion.ToString(); + var bundlePlatform = bundleSymbol.Platform.ToString().ToLower(); + var bundleDescription = bundleSymbol.Name; + + using (var memoryStream = new MemoryStream()) + using (var writer = new XmlTextWriter(memoryStream, Encoding.UTF8)) + { + writer.WriteStartDocument(); - version.Load(bundleTempPath); - resources.Add(version); + writer.WriteStartElement("assembly", asmv1Namespace); + writer.WriteAttributeString("manifestVersion", "1.0"); + + writer.WriteStartElement("assemblyIdentity"); + writer.WriteAttributeString("name", bundleFileName); + writer.WriteAttributeString("version", bundleAssemblyVersion); + writer.WriteAttributeString("processorArchitecture", bundlePlatform); + writer.WriteAttributeString("type", "win32"); + writer.WriteEndElement(); // + + if (!String.IsNullOrEmpty(bundleDescription)) + { + writer.WriteStartElement("description"); + writer.WriteString(bundleDescription); + writer.WriteEndElement(); + } + + writer.WriteStartElement("dependency"); + writer.WriteStartElement("dependentAssembly"); + writer.WriteStartElement("assemblyIdentity"); + writer.WriteAttributeString("name", "Microsoft.Windows.Common-Controls"); + writer.WriteAttributeString("version", "6.0.0.0"); + writer.WriteAttributeString("processorArchitecture", bundlePlatform); + writer.WriteAttributeString("publicKeyToken", "6595b64144ccf1df"); + writer.WriteAttributeString("language", "*"); + writer.WriteAttributeString("type", "win32"); + writer.WriteEndElement(); // + writer.WriteEndElement(); // + writer.WriteEndElement(); // + + writer.WriteStartElement("compatibility", compatv1Namespace); + writer.WriteStartElement("application"); + + writer.WriteStartElement("supportedOS"); + writer.WriteAttributeString("Id", "{e2011457-1546-43c5-a5fe-008deee3d3f0}"); // Windows Vista + writer.WriteEndElement(); + writer.WriteStartElement("supportedOS"); + writer.WriteAttributeString("Id", "{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"); // Windows 7 + writer.WriteEndElement(); + writer.WriteStartElement("supportedOS"); + writer.WriteAttributeString("Id", "{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"); // Windows 8 + writer.WriteEndElement(); + writer.WriteStartElement("supportedOS"); + writer.WriteAttributeString("Id", "{1f676c76-80e1-4239-95bb-83d0f6d0da78}"); // Windows 8.1 + writer.WriteEndElement(); + writer.WriteStartElement("supportedOS"); + writer.WriteAttributeString("Id", "{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"); // Windows 10 + writer.WriteEndElement(); + + writer.WriteEndElement(); // + writer.WriteEndElement(); // + + writer.WriteStartElement("trustInfo", asmv3Namespace); + writer.WriteStartElement("security"); + writer.WriteStartElement("requestedPrivileges"); + writer.WriteStartElement("requestedExecutionLevel"); + writer.WriteAttributeString("level", "asInvoker"); + writer.WriteAttributeString("uiAccess", "false"); + writer.WriteEndElement(); // + writer.WriteEndElement(); // + writer.WriteEndElement(); // + writer.WriteEndElement(); // + + writer.WriteStartElement("application", asmv3Namespace); + writer.WriteStartElement("windowsSettings"); + writer.WriteStartElement("dpiAware", ws2005Namespace); + writer.WriteString("true"); + writer.WriteEndElement(); // + writer.WriteEndElement(); // + writer.WriteEndElement(); // + + writer.WriteEndDocument(); // + writer.Close(); + + return memoryStream.ToArray(); + } + } + private static Version GetWindowsAssemblyVersion(WixBundleSymbol bundleSymbol) + { // Ensure the bundle info provides a full four part version. - var fourPartVersion = new Version(bundleInfo.Version); + var fourPartVersion = new Version(bundleSymbol.Version); var major = (fourPartVersion.Major < 0) ? 0 : fourPartVersion.Major; var minor = (fourPartVersion.Minor < 0) ? 0 : fourPartVersion.Minor; var build = (fourPartVersion.Build < 0) ? 0 : fourPartVersion.Build; @@ -108,14 +207,25 @@ namespace WixToolset.Core.Burn.Bundles if (UInt16.MaxValue < major || UInt16.MaxValue < minor || UInt16.MaxValue < build || UInt16.MaxValue < revision) { - throw new WixException(ErrorMessages.InvalidModuleOrBundleVersion(bundleInfo.SourceLineNumbers, "Bundle", bundleInfo.Version)); + throw new WixException(ErrorMessages.InvalidModuleOrBundleVersion(bundleSymbol.SourceLineNumbers, "Bundle", bundleSymbol.Version)); } - fourPartVersion = new Version(major, minor, build, revision); - version.FileVersion = fourPartVersion; - version.ProductVersion = fourPartVersion; + return new Version(major, minor, build, revision); + } + + private static void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleSymbol bundleInfo, Version windowsAssemblyVersion, byte[] applicationManifestData) + { + const int burnLocale = 1033; + var resources = new Dtf.Resources.ResourceCollection(); + var version = new Dtf.Resources.VersionResource("#1", burnLocale); + + version.Load(bundleTempPath); + resources.Add(version); + + version.FileVersion = windowsAssemblyVersion; + version.ProductVersion = windowsAssemblyVersion; - var strings = version[1033] ?? version.Add(1033); + var strings = version[burnLocale] ?? version.Add(burnLocale); strings["LegalCopyright"] = bundleInfo.Copyright; strings["OriginalFilename"] = Path.GetFileName(outputPath); strings["FileVersion"] = bundleInfo.Version; // string versions do not have to be four parts. @@ -138,7 +248,7 @@ namespace WixToolset.Core.Burn.Bundles if (!String.IsNullOrEmpty(bundleInfo.IconSourceFile)) { - var iconGroup = new Dtf.Resources.GroupIconResource("#1", 1033); + var iconGroup = new Dtf.Resources.GroupIconResource("#1", burnLocale); iconGroup.ReadFromFile(bundleInfo.IconSourceFile); resources.Add(iconGroup); @@ -150,11 +260,14 @@ namespace WixToolset.Core.Burn.Bundles if (!String.IsNullOrEmpty(bundleInfo.SplashScreenSourceFile)) { - var bitmap = new Dtf.Resources.BitmapResource("#1", 1033); + var bitmap = new Dtf.Resources.BitmapResource("#1", burnLocale); bitmap.ReadFromFile(bundleInfo.SplashScreenSourceFile); resources.Add(bitmap); } + var manifestResource = new Resource(ResourceType.Manifest, "#1", burnLocale, applicationManifestData); + resources.Add(manifestResource); + resources.Save(bundleTempPath); } } diff --git a/src/test/WixToolsetTest.CoreIntegration/BundleFixture.cs b/src/test/WixToolsetTest.CoreIntegration/BundleFixture.cs index cf57eae1..9c5ec6ec 100644 --- a/src/test/WixToolsetTest.CoreIntegration/BundleFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/BundleFixture.cs @@ -13,6 +13,7 @@ namespace WixToolsetTest.CoreIntegration using WixToolset.Data; using WixToolset.Data.Burn; using WixToolset.Data.Symbols; + using WixToolset.Dtf.Resources; using Xunit; public class BundleFixture @@ -115,6 +116,19 @@ namespace WixToolsetTest.CoreIntegration "" + "", registrationElement.GetTestXml()); } + + var manifestResource = new Resource(ResourceType.Manifest, "#1", 1033); + manifestResource.Load(exePath); + var actualManifestData = Encoding.UTF8.GetString(manifestResource.Data); + Assert.Equal("" + + "" + + "" + + "~TestBundle" + + "" + + "" + + "" + + "true" + + "", actualManifestData); } } -- cgit v1.2.3-55-g6feb