From 60d7baefb4e87bf0ddaae58a653faee0be0429f6 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Mon, 1 Jan 2018 10:30:42 -0800 Subject: Initial code commit --- src/wixext/NetFxCompiler.cs | 159 ++++++++++++++ src/wixext/NetFxDecompiler.cs | 139 ++++++++++++ src/wixext/NetFxExtensionData.cs | 25 +++ src/wixext/NetfxExtensionFactory.cs | 18 ++ .../NetfxWindowsInstallerBackendExtension.cs | 27 +++ src/wixext/Tuples/NetFxNativeImageTuple.cs | 65 ++++++ src/wixext/Tuples/NetfxTupleDefinitions.cs | 27 +++ src/wixext/WixToolset.Netfx.wixext.csproj | 35 +++ src/wixext/WixToolset.Netfx.wixext.targets | 11 + src/wixext/netfx.xsd | 235 +++++++++++++++++++++ 10 files changed, 741 insertions(+) create mode 100644 src/wixext/NetFxCompiler.cs create mode 100644 src/wixext/NetFxDecompiler.cs create mode 100644 src/wixext/NetFxExtensionData.cs create mode 100644 src/wixext/NetfxExtensionFactory.cs create mode 100644 src/wixext/NetfxWindowsInstallerBackendExtension.cs create mode 100644 src/wixext/Tuples/NetFxNativeImageTuple.cs create mode 100644 src/wixext/Tuples/NetfxTupleDefinitions.cs create mode 100644 src/wixext/WixToolset.Netfx.wixext.csproj create mode 100644 src/wixext/WixToolset.Netfx.wixext.targets create mode 100644 src/wixext/netfx.xsd (limited to 'src/wixext') diff --git a/src/wixext/NetFxCompiler.cs b/src/wixext/NetFxCompiler.cs new file mode 100644 index 00000000..55db4297 --- /dev/null +++ b/src/wixext/NetFxCompiler.cs @@ -0,0 +1,159 @@ +// 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. + +namespace WixToolset.Netfx +{ + using System; + using System.Collections.Generic; + using System.Xml.Linq; + using WixToolset.Data; + using WixToolset.Extensibility; + + /// + /// The compiler for the WiX Toolset .NET Framework Extension. + /// + public sealed class NetfxCompiler : BaseCompilerExtension + { + public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/netfx"; + + /// + /// Processes an element for the Compiler. + /// + /// Parent element of element to process. + /// Element to process. + /// Extra information about the context in which this element is being parsed. + public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context) + { + switch (parentElement.Name.LocalName) + { + case "File": + string fileId = context["FileId"]; + + switch (element.Name.LocalName) + { + case "NativeImage": + this.ParseNativeImageElement(intermediate, section, element, fileId); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + } + + /// + /// Parses a NativeImage element. + /// + /// The element to parse. + /// The file identifier of the parent element. + private void ParseNativeImageElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId) + { + SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string appBaseDirectory = null; + string assemblyApplication = null; + int attributes = 0x8; // 32bit is on by default + int priority = 3; + + foreach (XAttribute attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "AppBaseDirectory": + appBaseDirectory = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + + // See if a formatted value is specified. + if (-1 == appBaseDirectory.IndexOf("[", StringComparison.Ordinal)) + { + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "Directory", appBaseDirectory); + } + break; + case "AssemblyApplication": + assemblyApplication = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + + // See if a formatted value is specified. + if (-1 == assemblyApplication.IndexOf("[", StringComparison.Ordinal)) + { + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "File", assemblyApplication); + } + break; + case "Debug": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 0x1; + } + break; + case "Dependencies": + if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 0x2; + } + break; + case "Platform": + string platformValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + if (0 < platformValue.Length) + { + switch (platformValue) + { + case "32bit": + // 0x8 is already on by default + break; + case "64bit": + attributes &= ~0x8; + attributes |= 0x10; + break; + case "all": + attributes |= 0x10; + break; + } + } + break; + case "Priority": + priority = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 3); + break; + case "Profile": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 0x4; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "NetFxScheduleNativeImage"); + + if (!this.Messaging.EncounteredError) + { + var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "NetFxNativeImage", id); + row.Set(1, fileId); + row.Set(2, priority); + row.Set(3, attributes); + row.Set(4, assemblyApplication); + row.Set(5, appBaseDirectory); + } + } + } +} diff --git a/src/wixext/NetFxDecompiler.cs b/src/wixext/NetFxDecompiler.cs new file mode 100644 index 00000000..e30905d1 --- /dev/null +++ b/src/wixext/NetFxDecompiler.cs @@ -0,0 +1,139 @@ +// 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. + +namespace WixToolset.Extensions +{ +#if TODO_CONSIDER_DECOMPILER + using System; + using System.Collections; + using System.Diagnostics; + using System.Globalization; + using WixToolset.Data; + using WixToolset.Extensibility; + using NetFx = WixToolset.Extensions.Serialize.NetFx; + using Wix = WixToolset.Data.Serialize; + + /// + /// The decompiler for the WiX Toolset .NET Framework Extension. + /// + public sealed class NetFxDecompiler : DecompilerExtension + { + /// + /// Creates a decompiler for NetFx Extension. + /// + public NetFxDecompiler() + { + this.TableDefinitions = NetFxExtensionData.GetExtensionTableDefinitions(); + } + + /// + /// Get the extensions library to be removed. + /// + /// Table definitions for library. + /// Library to remove from decompiled output. + public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions) + { + return NetFxExtensionData.GetExtensionLibrary(tableDefinitions); + } + + /// + /// Decompiles an extension table. + /// + /// The table to decompile. + public override void DecompileTable(Table table) + { + switch (table.Name) + { + case "NetFxNativeImage": + this.DecompileNetFxNativeImageTable(table); + break; + default: + base.DecompileTable(table); + break; + } + } + + /// + /// Decompile the NetFxNativeImage table. + /// + /// The table to decompile. + private void DecompileNetFxNativeImageTable(Table table) + { + foreach (Row row in table.Rows) + { + NetFx.NativeImage nativeImage = new NetFx.NativeImage(); + + nativeImage.Id = (string)row[0]; + + switch ((int)row[2]) + { + case 0: + nativeImage.Priority = NetFx.NativeImage.PriorityType.Item0; + break; + case 1: + nativeImage.Priority = NetFx.NativeImage.PriorityType.Item1; + break; + case 2: + nativeImage.Priority = NetFx.NativeImage.PriorityType.Item2; + break; + case 3: + nativeImage.Priority = NetFx.NativeImage.PriorityType.Item3; + break; + } + + if (null != row[3]) + { + int attributes = (int)row[3]; + + if (0x1 == (attributes & 0x1)) + { + nativeImage.Debug = NetFx.YesNoType.yes; + } + + if (0x2 == (attributes & 0x2)) + { + nativeImage.Dependencies = NetFx.YesNoType.no; + } + + if (0x4 == (attributes & 0x4)) + { + nativeImage.Profile = NetFx.YesNoType.yes; + } + + if (0x8 == (attributes & 0x8) && 0x10 == (attributes & 0x10)) + { + nativeImage.Platform = NetFx.NativeImage.PlatformType.all; + } + else if (0x8 == (attributes & 0x8)) + { + nativeImage.Platform = NetFx.NativeImage.PlatformType.Item32bit; + } + else if (0x10 == (attributes & 0x10)) + { + nativeImage.Platform = NetFx.NativeImage.PlatformType.Item64bit; + } + } + + if (null != row[4]) + { + nativeImage.AssemblyApplication = (string)row[4]; + } + + if (null != row[5]) + { + nativeImage.AppBaseDirectory = (string)row[5]; + } + + Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", (string)row[1]); + if (null != file) + { + file.AddChild(nativeImage); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_", (string)row[1], "File")); + } + } + } + } +#endif +} diff --git a/src/wixext/NetFxExtensionData.cs b/src/wixext/NetFxExtensionData.cs new file mode 100644 index 00000000..b68741fd --- /dev/null +++ b/src/wixext/NetFxExtensionData.cs @@ -0,0 +1,25 @@ +// 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. + +namespace WixToolset.Netfx +{ + using WixToolset.Data; + using WixToolset.Extensibility; + using WixToolset.Netfx.Tuples; + + /// + /// The WiX Toolset .NET Framework Extension. + /// + public sealed class NetfxExtensionData : BaseExtensionData + { + public override bool TryGetTupleDefinitionByName(string name, out IntermediateTupleDefinition tupleDefinition) + { + tupleDefinition = (name == NetfxTupleDefinitionNames.NetFxNativeImage) ? NetfxTupleDefinitions.NetFxNativeImage : null; + return tupleDefinition != null; + } + + public override Intermediate GetLibrary(ITupleDefinitionCreator tupleDefinitions) + { + return Intermediate.Load(typeof(NetfxExtensionData).Assembly, "WixToolset.Netfx.netfx.wixlib", tupleDefinitions); + } + } +} diff --git a/src/wixext/NetfxExtensionFactory.cs b/src/wixext/NetfxExtensionFactory.cs new file mode 100644 index 00000000..756d1b2a --- /dev/null +++ b/src/wixext/NetfxExtensionFactory.cs @@ -0,0 +1,18 @@ +// 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. + +namespace WixToolset.Netfx +{ + using System; + using System.Collections.Generic; + using WixToolset.Extensibility; + + public class NetfxExtensionFactory : BaseExtensionFactory + { + protected override IEnumerable ExtensionTypes => new[] + { + typeof(NetfxCompiler), + typeof(NetfxExtensionData), + typeof(NetfxWindowsInstallerBackendExtension), + }; + } +} diff --git a/src/wixext/NetfxWindowsInstallerBackendExtension.cs b/src/wixext/NetfxWindowsInstallerBackendExtension.cs new file mode 100644 index 00000000..50266ef4 --- /dev/null +++ b/src/wixext/NetfxWindowsInstallerBackendExtension.cs @@ -0,0 +1,27 @@ +// 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. + +namespace WixToolset.Netfx +{ + using WixToolset.Data.WindowsInstaller; + using WixToolset.Extensibility; + + public class NetfxWindowsInstallerBackendExtension : BaseWindowsInstallerBackendExtension + { + private static readonly TableDefinition[] Tables = new[] { + new TableDefinition( + "NetFxNativeImage", + new[] + { + new ColumnDefinition("NetFxNativeImage", ColumnType.String, 72, true, false, ColumnCategory.Identifier, description: "The primary key, a non-localized token."), + new ColumnDefinition("File_", ColumnType.String, 0, false, false, ColumnCategory.Identifier, keyTable:"File", keyColumn: 1, description: "The assembly for which a native image will be generated."), + new ColumnDefinition("Priority", ColumnType.Number, 2, false, false, ColumnCategory.Integer, maxValue: 3, description: "The priority for generating this native image: 0 is syncronous, 1-3 represent various levels of queued generation."), + new ColumnDefinition("Attributes", ColumnType.Number, 4, false, false, ColumnCategory.Integer, maxValue: 2147483647, description: "Integer containing bit flags representing native image attributes."), + new ColumnDefinition("File_Application", ColumnType.String, 72, false, true, ColumnCategory.Formatted, description: "The application which loads this assembly."), + new ColumnDefinition("Directory_ApplicationBase", ColumnType.String, 72, false, true, ColumnCategory.Formatted, description: "The directory containing the application which loads this assembly."), + } + ), + }; + + protected override TableDefinition[] TableDefinitionsForTuples => Tables; + } +} diff --git a/src/wixext/Tuples/NetFxNativeImageTuple.cs b/src/wixext/Tuples/NetFxNativeImageTuple.cs new file mode 100644 index 00000000..af507137 --- /dev/null +++ b/src/wixext/Tuples/NetFxNativeImageTuple.cs @@ -0,0 +1,65 @@ +// 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. + +namespace WixToolset.Netfx.Tuples +{ + using WixToolset.Data; + + public enum NetFxNativeImageTupleFields + { + NetFxNativeImage, + File_, + Priority, + Attributes, + File_Application, + Directory_ApplicationBase, + } + + public class NetFxNativeImageTuple : IntermediateTuple + { + public NetFxNativeImageTuple() : base(NetfxTupleDefinitions.NetFxNativeImage, null, null) + { + } + + public NetFxNativeImageTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(NetfxTupleDefinitions.NetFxNativeImage, sourceLineNumber, id) + { + } + + public IntermediateField this[NetFxNativeImageTupleFields index] => this.Fields[(int)index]; + + public string NetFxNativeImage + { + get => this.Fields[(int)NetFxNativeImageTupleFields.NetFxNativeImage].AsString(); + set => this.Set((int)NetFxNativeImageTupleFields.NetFxNativeImage, value); + } + + public string File_ + { + get => this.Fields[(int)NetFxNativeImageTupleFields.File_].AsString(); + set => this.Set((int)NetFxNativeImageTupleFields.File_, value); + } + + public int Priority + { + get => this.Fields[(int)NetFxNativeImageTupleFields.Priority].AsNumber(); + set => this.Set((int)NetFxNativeImageTupleFields.Priority, value); + } + + public int Attributes + { + get => this.Fields[(int)NetFxNativeImageTupleFields.Attributes].AsNumber(); + set => this.Set((int)NetFxNativeImageTupleFields.Attributes, value); + } + + public string File_Application + { + get => this.Fields[(int)NetFxNativeImageTupleFields.File_Application].AsString(); + set => this.Set((int)NetFxNativeImageTupleFields.File_Application, value); + } + + public string Directory_ApplicationBase + { + get => this.Fields[(int)NetFxNativeImageTupleFields.Directory_ApplicationBase].AsString(); + set => this.Set((int)NetFxNativeImageTupleFields.Directory_ApplicationBase, value); + } + } +} \ No newline at end of file diff --git a/src/wixext/Tuples/NetfxTupleDefinitions.cs b/src/wixext/Tuples/NetfxTupleDefinitions.cs new file mode 100644 index 00000000..aa584b38 --- /dev/null +++ b/src/wixext/Tuples/NetfxTupleDefinitions.cs @@ -0,0 +1,27 @@ +// 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. + +namespace WixToolset.Netfx.Tuples +{ + using WixToolset.Data; + + public static class NetfxTupleDefinitionNames + { + public static string NetFxNativeImage { get; } = "NetFxNativeImage"; + } + + public static class NetfxTupleDefinitions + { + public static readonly IntermediateTupleDefinition NetFxNativeImage = new IntermediateTupleDefinition( + NetfxTupleDefinitionNames.NetFxNativeImage, + new[] + { + new IntermediateFieldDefinition(nameof(NetFxNativeImageTupleFields.NetFxNativeImage), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(NetFxNativeImageTupleFields.File_), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(NetFxNativeImageTupleFields.Priority), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(NetFxNativeImageTupleFields.Attributes), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(NetFxNativeImageTupleFields.File_Application), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(NetFxNativeImageTupleFields.Directory_ApplicationBase), IntermediateFieldType.String), + }, + typeof(NetFxNativeImageTuple)); + } +} diff --git a/src/wixext/WixToolset.Netfx.wixext.csproj b/src/wixext/WixToolset.Netfx.wixext.csproj new file mode 100644 index 00000000..d925e348 --- /dev/null +++ b/src/wixext/WixToolset.Netfx.wixext.csproj @@ -0,0 +1,35 @@ + + + + + + netstandard2.0 + WixToolset.Netfx + WiX Toolset .NET Framework Extension + WiX Toolset .NET Framework Extension + true + build + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wixext/WixToolset.Netfx.wixext.targets b/src/wixext/WixToolset.Netfx.wixext.targets new file mode 100644 index 00000000..17312abf --- /dev/null +++ b/src/wixext/WixToolset.Netfx.wixext.targets @@ -0,0 +1,11 @@ + + + + + + $(MSBuildThisFileDirectory)..\tools\WixToolset.Netfx.wixext.dll" + + + + + diff --git a/src/wixext/netfx.xsd b/src/wixext/netfx.xsd new file mode 100644 index 00000000..6ef4e9b6 --- /dev/null +++ b/src/wixext/netfx.xsd @@ -0,0 +1,235 @@ + + + + + + + + The source code schema for the WiX Toolset .NET Framework Extension. + + + + + + + Improves the performance of managed applications by creating native images. + Requires the .NET Framework 2.0 or newer to be installed on the target machine since + it runs NGen. + + + + + + Native images are files containing compiled processor-specific machine code, which + are installed into the native image cache on the local computer. The runtime + can use native images from the cache instead using the just-in-time (JIT) + compiler to compile the original assembly. + + + The native image custom actions are configured to ignore failures so that failing + to generate or remove a native image will not cause setup to fail and roll back. + + + Note for patches: if you built your target, or baseline, MSI with + previous versions 3.0 or 3.5 of this extension and want to upgrade to formattable + values for @AssemblyApplication or @AppBaseDirectory you must also include a + BinaryRef to "NetFxCA" to pull in necessary changes. If you do use formattable + values and do not include the binary changes ngen.exe will not optimize your + native images for the specified application. + + + This should be a rare occurrence, however. Because you cannot remove components + in a patch - and pyro does validate you do not - it is not practical to switch + from using identifiers to formattable values in a patch. One practical possibility + is if you wanted to use a different application to optimize your native images + and that application is not already installed with the MSI to be updated. + + + + + + + + + The identifier for this NativeImage. + + + + + + + + The directory to use for locating dependent assemblies. + For DLL assemblies and assemblies installed to the Global Assembly Cache (GAC), + this attribute should be set to the directory of the application which loads this + assembly. For EXE assemblies, this attribute does not need to be set because NGen + will use the directory of the assembly file by default. + + + The value can be in the form of a directory identifier, or a formatted string + that resolves to either a directory identifier or a full path to a directory. + + + + + + + + + The application which will load this assembly. + For DLL assemblies which are loaded via reflection, this attribute should + be set to indicate the application which will load this assembly. + The configuration of the application (usually specified via an exe.config file) will be used + to determine how to resolve dependencies for this assembly. + + + The value can be in the form of a file identifier, or a formatted string + that resolves to either a file identifier or a full path to a file. + + + When a shared component is loaded at run time, using the Load method, the + application's configuration file determines the dependencies that are loaded + for the shared component — for example, the version of a dependency that is loaded. + This attribute gives guidance on which dependencies would be loaded at run time in order + to figure out which dependency assemblies will also need to have native images generated + (assuming the Dependency attribute is not set to "no"). + + + This attribute cannot be set if the AssemblyApplication attribute is set on the parent + File element (please note that these attributes both refer to the same application + assembly but do very different things: specifiying File/@AssemblyApplication will force + an assembly to install to a private location next to the indicated application, whereas + this AssemblyApplication attribute will be used to help resolve dependent assemblies + while generating native images for this assembly). + + + + + + + + Set to "yes" to generate native images that can be used under a debugger. + The default value is "no". + + + + + + + Set to "no" to generate the minimum number of native images. + The default value is "yes". + + + + + + + Sets the platform(s) for which native images will be generated. + + + + + + + + Attempt to generate native images only for the 32-bit version of the .NET Framework + on the target machine. If the 32-bit version of the .NET Framework 2.0 or newer is not + present on the target machine, native image custom actions will not be scheduled. + This is the default value. + + + + + + + Attempt to generate native images only for the 64-bit version of the .NET Framework + on the target machine. If a 64-bit version of the .NET Framework 2.0 or newer is not + present on the target machine, native image custom actions will not be scheduled. + + + + + + + Attempt to generate native images for the 32-bit and 64-bit versions of the .NET Framework + on the target machine. If a version of the .NET Framework 2.0 or newer is not present on the + target machine for a processor architecture, native image custom actions will not be + scheduled for that processor architecture. + + + + + + + + + + Sets the priority of generating the native images for this assembly. + + + + + + + + This is the highest priority, it means that image generation occurs syncronously + during the setup process. This option will slow down setup performance. + + + + + + + This will queue image generation to the NGen service to occur immediately. + This option will slow down setup performance. + + + + + + + This will queue image generation to the NGen service to occur after all priority 1 + assemblies have completed. + This option will slow down setup performance. + + + + + + + This is the lowest priority, it will queue image generation to occur when the + machine is idle. + This option should not slow down setup performance. + This is the default value. + + + + + + + + + + Set to "yes" to generate native images that can be used under a profiler. + The default value is "no". + + + + + + + + + Values of this type will either be "yes" or "no". + + + + + + + + -- cgit v1.2.3-55-g6feb