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