From 39e930d9aaff250e0fd5019eeedaa40717a6c6fe Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Wed, 29 Apr 2020 19:28:50 +1000 Subject: Add DotNetCoreBootstrapperApplicationHost for an SCD-style .NET Core BA. --- .../BootstrapperApplicationFactory.cs | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs (limited to 'src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs') diff --git a/src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs b/src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs new file mode 100644 index 00000000..0c6ea367 --- /dev/null +++ b/src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs @@ -0,0 +1,87 @@ +// 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.Dnc.Host +{ + using System; + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + + /// + /// Entry point for the .NET Core host to create and return the BA to the engine. + /// Reflection is used instead of referencing WixToolset.Mba.Core directly to avoid requiring it in the AssemblyLoadContext. + /// + public sealed class BootstrapperApplicationFactory : IBootstrapperApplicationFactory + { + private string baFactoryAssemblyName; + private string baFactoryAssemblyPath; + + public BootstrapperApplicationFactory(string baFactoryAssemblyName, string baFactoryAssemblyPath) + { + this.baFactoryAssemblyName = baFactoryAssemblyName; + this.baFactoryAssemblyPath = baFactoryAssemblyPath; + } + + /// + /// Loads the bootstrapper application assembly and calls its IBootstrapperApplicationFactory.Create method. + /// + /// Pointer to BOOTSTRAPPER_CREATE_ARGS struct. + /// Pointer to BOOTSTRAPPER_CREATE_RESULTS struct. + /// The bootstrapper application assembly + /// does not define the . + public void Create(IntPtr pArgs, IntPtr pResults) + { + // Load the BA's IBootstrapperApplicationFactory. + var baFactoryType = BootstrapperApplicationFactory.GetBAFactoryTypeFromAssembly(this.baFactoryAssemblyName, this.baFactoryAssemblyPath); + var baFactory = Activator.CreateInstance(baFactoryType); + if (null == baFactory) + { + throw new InvalidBootstrapperApplicationFactoryException(); + } + + var createMethod = baFactoryType.GetMethod(nameof(Create), new[] { typeof(IntPtr), typeof(IntPtr) }); + if (null == createMethod) + { + throw new InvalidBootstrapperApplicationFactoryException(); + } + createMethod.Invoke(baFactory, new object[] { pArgs, pResults }); + } + + /// + /// Locates the and returns the specified type. + /// + /// The assembly that defines the IBootstrapperApplicationFactory implementation. + /// The bootstrapper application factory . + private static Type GetBAFactoryTypeFromAssembly(string assemblyName, string assemblyPath) + { + // The default ALC shouldn't need help loading the assembly, since the host should have provided the deps.json + // when starting the runtime. But it doesn't hurt so keep this in case an isolated ALC is ever needed. + var alc = new DnchostAssemblyLoadContext(assemblyPath, false); + var asm = alc.LoadFromAssemblyName(new AssemblyName(assemblyName)); + + var attr = asm.GetCustomAttributes() + .Where(a => a.GetType().FullName == "WixToolset.Mba.Core.BootstrapperApplicationFactoryAttribute") + .SingleOrDefault(); + + if (null == attr) + { + throw new MissingAttributeException(); + } + + var baFactoryTypeProperty = attr.GetType().GetProperty("BootstrapperApplicationFactoryType", typeof(Type)); + if (baFactoryTypeProperty == null || baFactoryTypeProperty.GetMethod == null) + { + throw new MissingAttributeException(); + } + + var baFactoryType = (Type)baFactoryTypeProperty.GetMethod.Invoke(attr, null); + return baFactoryType; + } + + // Entry point for the DNC host. + public static IBootstrapperApplicationFactory CreateBAFactory([MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyName, [MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyPath) + { + return new BootstrapperApplicationFactory(baFactoryAssemblyName, baFactoryAssemblyPath); + } + } +} -- cgit v1.2.3-55-g6feb