@joebigelow / wix-1 / commits / 2a87b3e7

Generate the bundle's application manifest in the Burn backend.

Sean Hall committed Jul 19, 2020 at 15:05 UTC 2a87b3e728fb56202d21d402cecc0bceeac49ade
3 files changed +143 -16
src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+1 -1
@@ -475,7 +475,7 @@ namespace WixToolset.Core.Burn
475 }
476
477 {
478 - var command = new CreateBundleExeCommand(this.Messaging, this.BackendHelper, this.IntermediateFolder, this.OutputPath, bundleSymbol, uxContainer, containers);
478 + var command = new CreateBundleExeCommand(this.Messaging, this.BackendHelper, this.IntermediateFolder, this.OutputPath, bundleApplicationSymbol, bundleSymbol, uxContainer, containers);
479 command.Execute();
480
481 fileTransfers.Add(command.Transfer);
src/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs
+128 -15
@@ -6,20 +6,24 @@ namespace WixToolset.Core.Burn.Bundles
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Reflection;
9 + using System.Text;
10 + using System.Xml;
11 using WixToolset.Data;
12 using WixToolset.Data.Burn;
13 using WixToolset.Data.Symbols;
14 + using WixToolset.Dtf.Resources;
15 using WixToolset.Extensibility.Data;
16 using WixToolset.Extensibility.Services;
17
18 internal class CreateBundleExeCommand
19 {
17 - public CreateBundleExeCommand(IMessaging messaging, IBackendHelper backendHelper, string intermediateFolder, string outputPath, WixBundleSymbol bundleSymbol, WixBundleContainerSymbol uxContainer, IEnumerable<WixBundleContainerSymbol> containers)
20 + public CreateBundleExeCommand(IMessaging messaging, IBackendHelper backendHelper, string intermediateFolder, string outputPath, WixBootstrapperApplicationSymbol bootstrapperApplicationSymbol, WixBundleSymbol bundleSymbol, WixBundleContainerSymbol uxContainer, IEnumerable<WixBundleContainerSymbol> containers)
21 {
22 this.Messaging = messaging;
23 this.BackendHelper = backendHelper;
24 this.IntermediateFolder = intermediateFolder;
25 this.OutputPath = outputPath;
26 + this.BootstrapperApplicationSymbol = bootstrapperApplicationSymbol;
27 this.BundleSymbol = bundleSymbol;
28 this.UXContainer = uxContainer;
29 this.Containers = containers;
@@ -35,6 +39,8 @@ namespace WixToolset.Core.Burn.Bundles
39
40 private string OutputPath { get; }
41
42 + private WixBootstrapperApplicationSymbol BootstrapperApplicationSymbol { get; }
43 +
44 private WixBundleSymbol BundleSymbol { get; }
45
46 private WixBundleContainerSymbol UXContainer { get; }
@@ -64,7 +70,11 @@ namespace WixToolset.Core.Burn.Bundles
70 File.Copy(stubFile, bundleTempPath, true);
71 File.SetAttributes(bundleTempPath, FileAttributes.Normal);
72
67 - this.UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleSymbol);
73 + var windowsAssemblyVersion = GetWindowsAssemblyVersion(this.BundleSymbol);
74 +
75 + var applicationManifestData = GenerateApplicationManifest(this.BundleSymbol, this.BootstrapperApplicationSymbol, this.OutputPath, windowsAssemblyVersion);
76 +
77 + UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleSymbol, windowsAssemblyVersion, applicationManifestData);
78
79 // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers
80 // if they should be attached.
@@ -91,16 +101,105 @@ namespace WixToolset.Core.Burn.Bundles
101 }
102 }
103
94 - private void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleSymbol bundleInfo)
104 + private static byte[] GenerateApplicationManifest(WixBundleSymbol bundleSymbol, WixBootstrapperApplicationSymbol bootstrapperApplicationSymbol, string outputPath, Version windowsAssemblyVersion)
105 {
96 - var resources = new Dtf.Resources.ResourceCollection();
97 - var version = new Dtf.Resources.VersionResource("#1", 1033);
106 + const string asmv1Namespace = "urn:schemas-microsoft-com:asm.v1";
107 + const string asmv3Namespace = "urn:schemas-microsoft-com:asm.v3";
108 + const string compatv1Namespace = "urn:schemas-microsoft-com:compatibility.v1";
109 + const string ws2005Namespace = "http://schemas.microsoft.com/SMI/2005/WindowsSettings";
110 +
111 + var bundleFileName = Path.GetFileName(outputPath);
112 + var bundleAssemblyVersion = windowsAssemblyVersion.ToString();
113 + var bundlePlatform = bundleSymbol.Platform.ToString().ToLower();
114 + var bundleDescription = bundleSymbol.Name;
115 +
116 + using (var memoryStream = new MemoryStream())
117 + using (var writer = new XmlTextWriter(memoryStream, Encoding.UTF8))
118 + {
119 + writer.WriteStartDocument();
120
99 - version.Load(bundleTempPath);
100 - resources.Add(version);
121 + writer.WriteStartElement("assembly", asmv1Namespace);
122 + writer.WriteAttributeString("manifestVersion", "1.0");
123 +
124 + writer.WriteStartElement("assemblyIdentity");
125 + writer.WriteAttributeString("name", bundleFileName);
126 + writer.WriteAttributeString("version", bundleAssemblyVersion);
127 + writer.WriteAttributeString("processorArchitecture", bundlePlatform);
128 + writer.WriteAttributeString("type", "win32");
129 + writer.WriteEndElement(); // </assemblyIdentity>
130 +
131 + if (!String.IsNullOrEmpty(bundleDescription))
132 + {
133 + writer.WriteStartElement("description");
134 + writer.WriteString(bundleDescription);
135 + writer.WriteEndElement();
136 + }
137 +
138 + writer.WriteStartElement("dependency");
139 + writer.WriteStartElement("dependentAssembly");
140 + writer.WriteStartElement("assemblyIdentity");
141 + writer.WriteAttributeString("name", "Microsoft.Windows.Common-Controls");
142 + writer.WriteAttributeString("version", "6.0.0.0");
143 + writer.WriteAttributeString("processorArchitecture", bundlePlatform);
144 + writer.WriteAttributeString("publicKeyToken", "6595b64144ccf1df");
145 + writer.WriteAttributeString("language", "*");
146 + writer.WriteAttributeString("type", "win32");
147 + writer.WriteEndElement(); // </assemblyIdentity>
148 + writer.WriteEndElement(); // </dependentAssembly>
149 + writer.WriteEndElement(); // </dependency>
150 +
151 + writer.WriteStartElement("compatibility", compatv1Namespace);
152 + writer.WriteStartElement("application");
153 +
154 + writer.WriteStartElement("supportedOS");
155 + writer.WriteAttributeString("Id", "{e2011457-1546-43c5-a5fe-008deee3d3f0}"); // Windows Vista
156 + writer.WriteEndElement();
157 + writer.WriteStartElement("supportedOS");
158 + writer.WriteAttributeString("Id", "{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"); // Windows 7
159 + writer.WriteEndElement();
160 + writer.WriteStartElement("supportedOS");
161 + writer.WriteAttributeString("Id", "{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"); // Windows 8
162 + writer.WriteEndElement();
163 + writer.WriteStartElement("supportedOS");
164 + writer.WriteAttributeString("Id", "{1f676c76-80e1-4239-95bb-83d0f6d0da78}"); // Windows 8.1
165 + writer.WriteEndElement();
166 + writer.WriteStartElement("supportedOS");
167 + writer.WriteAttributeString("Id", "{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"); // Windows 10
168 + writer.WriteEndElement();
169 +
170 + writer.WriteEndElement(); // </application>
171 + writer.WriteEndElement(); // </compatibility>
172 +
173 + writer.WriteStartElement("trustInfo", asmv3Namespace);
174 + writer.WriteStartElement("security");
175 + writer.WriteStartElement("requestedPrivileges");
176 + writer.WriteStartElement("requestedExecutionLevel");
177 + writer.WriteAttributeString("level", "asInvoker");
178 + writer.WriteAttributeString("uiAccess", "false");
179 + writer.WriteEndElement(); // </requestedExecutionLevel>
180 + writer.WriteEndElement(); // </requestedPrivileges>
181 + writer.WriteEndElement(); // </security>
182 + writer.WriteEndElement(); // </trustInfo>
183 +
184 + writer.WriteStartElement("application", asmv3Namespace);
185 + writer.WriteStartElement("windowsSettings");
186 + writer.WriteStartElement("dpiAware", ws2005Namespace);
187 + writer.WriteString("true");
188 + writer.WriteEndElement(); // </application>
189 + writer.WriteEndElement(); // </windowSettings>
190 + writer.WriteEndElement(); // </dpiAware>
191 +
192 + writer.WriteEndDocument(); // </assembly>
193 + writer.Close();
194 +
195 + return memoryStream.ToArray();
196 + }
197 + }
198
199 + private static Version GetWindowsAssemblyVersion(WixBundleSymbol bundleSymbol)
200 + {
201 // Ensure the bundle info provides a full four part version.
103 - var fourPartVersion = new Version(bundleInfo.Version);
202 + var fourPartVersion = new Version(bundleSymbol.Version);
203 var major = (fourPartVersion.Major < 0) ? 0 : fourPartVersion.Major;
204 var minor = (fourPartVersion.Minor < 0) ? 0 : fourPartVersion.Minor;
205 var build = (fourPartVersion.Build < 0) ? 0 : fourPartVersion.Build;
@@ -108,14 +207,25 @@ namespace WixToolset.Core.Burn.Bundles
207
208 if (UInt16.MaxValue < major || UInt16.MaxValue < minor || UInt16.MaxValue < build || UInt16.MaxValue < revision)
209 {
111 - throw new WixException(ErrorMessages.InvalidModuleOrBundleVersion(bundleInfo.SourceLineNumbers, "Bundle", bundleInfo.Version));
210 + throw new WixException(ErrorMessages.InvalidModuleOrBundleVersion(bundleSymbol.SourceLineNumbers, "Bundle", bundleSymbol.Version));
211 }
212
114 - fourPartVersion = new Version(major, minor, build, revision);
115 - version.FileVersion = fourPartVersion;
116 - version.ProductVersion = fourPartVersion;
213 + return new Version(major, minor, build, revision);
214 + }
215 +
216 + private static void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleSymbol bundleInfo, Version windowsAssemblyVersion, byte[] applicationManifestData)
217 + {
218 + const int burnLocale = 1033;
219 + var resources = new Dtf.Resources.ResourceCollection();
220 + var version = new Dtf.Resources.VersionResource("#1", burnLocale);
221 +
222 + version.Load(bundleTempPath);
223 + resources.Add(version);
224 +
225 + version.FileVersion = windowsAssemblyVersion;
226 + version.ProductVersion = windowsAssemblyVersion;
227
118 - var strings = version[1033] ?? version.Add(1033);
228 + var strings = version[burnLocale] ?? version.Add(burnLocale);
229 strings["LegalCopyright"] = bundleInfo.Copyright;
230 strings["OriginalFilename"] = Path.GetFileName(outputPath);
231 strings["FileVersion"] = bundleInfo.Version; // string versions do not have to be four parts.
@@ -138,7 +248,7 @@ namespace WixToolset.Core.Burn.Bundles
248
249 if (!String.IsNullOrEmpty(bundleInfo.IconSourceFile))
250 {
141 - var iconGroup = new Dtf.Resources.GroupIconResource("#1", 1033);
251 + var iconGroup = new Dtf.Resources.GroupIconResource("#1", burnLocale);
252 iconGroup.ReadFromFile(bundleInfo.IconSourceFile);
253 resources.Add(iconGroup);
254
@@ -150,11 +260,14 @@ namespace WixToolset.Core.Burn.Bundles
260
261 if (!String.IsNullOrEmpty(bundleInfo.SplashScreenSourceFile))
262 {
153 - var bitmap = new Dtf.Resources.BitmapResource("#1", 1033);
263 + var bitmap = new Dtf.Resources.BitmapResource("#1", burnLocale);
264 bitmap.ReadFromFile(bundleInfo.SplashScreenSourceFile);
265 resources.Add(bitmap);
266 }
267
268 + var manifestResource = new Resource(ResourceType.Manifest, "#1", burnLocale, applicationManifestData);
269 + resources.Add(manifestResource);
270 +
271 resources.Save(bundleTempPath);
272 }
273 }
src/test/WixToolsetTest.CoreIntegration/BundleFixture.cs
+14
@@ -13,6 +13,7 @@ namespace WixToolsetTest.CoreIntegration
13 using WixToolset.Data;
14 using WixToolset.Data.Burn;
15 using WixToolset.Data.Symbols;
16 + using WixToolset.Dtf.Resources;
17 using Xunit;
18
19 public class BundleFixture
@@ -115,6 +116,19 @@ namespace WixToolsetTest.CoreIntegration
116 "<Arp Register='yes' DisplayName='~TestBundle' DisplayVersion='1.0.0.0' Publisher='Example Corporation' />" +
117 "</Registration>", registrationElement.GetTestXml());
118 }
119 +
120 + var manifestResource = new Resource(ResourceType.Manifest, "#1", 1033);
121 + manifestResource.Load(exePath);
122 + var actualManifestData = Encoding.UTF8.GetString(manifestResource.Data);
123 + Assert.Equal("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
124 + "<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">" +
125 + "<assemblyIdentity name=\"test.exe\" version=\"1.0.0.0\" processorArchitecture=\"x86\" type=\"win32\" />" +
126 + "<description>~TestBundle</description>" +
127 + "<dependency><dependentAssembly><assemblyIdentity name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"x86\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\" type=\"win32\" /></dependentAssembly></dependency>" +
128 + "<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\"><application><supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" /><supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\" /><supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\" /><supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\" /><supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\" /></application></compatibility>" +
129 + "<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\"><security><requestedPrivileges><requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" /></requestedPrivileges></security></trustInfo>" +
130 + "<application xmlns=\"urn:schemas-microsoft-com:asm.v3\"><windowsSettings><dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true</dpiAware></windowsSettings></application>" +
131 + "</assembly>", actualManifestData);
132 }
133 }
134