diff options
Diffstat (limited to 'src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs')
| -rw-r--r-- | src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs | 87 |
1 files changed, 87 insertions, 0 deletions
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 @@ | |||
| 1 | // 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. | ||
| 2 | |||
| 3 | namespace WixToolset.Dnc.Host | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Linq; | ||
| 7 | using System.Reflection; | ||
| 8 | using System.Runtime.InteropServices; | ||
| 9 | |||
| 10 | /// <summary> | ||
| 11 | /// Entry point for the .NET Core host to create and return the BA to the engine. | ||
| 12 | /// Reflection is used instead of referencing WixToolset.Mba.Core directly to avoid requiring it in the AssemblyLoadContext. | ||
| 13 | /// </summary> | ||
| 14 | public sealed class BootstrapperApplicationFactory : IBootstrapperApplicationFactory | ||
| 15 | { | ||
| 16 | private string baFactoryAssemblyName; | ||
| 17 | private string baFactoryAssemblyPath; | ||
| 18 | |||
| 19 | public BootstrapperApplicationFactory(string baFactoryAssemblyName, string baFactoryAssemblyPath) | ||
| 20 | { | ||
| 21 | this.baFactoryAssemblyName = baFactoryAssemblyName; | ||
| 22 | this.baFactoryAssemblyPath = baFactoryAssemblyPath; | ||
| 23 | } | ||
| 24 | |||
| 25 | /// <summary> | ||
| 26 | /// Loads the bootstrapper application assembly and calls its IBootstrapperApplicationFactory.Create method. | ||
| 27 | /// </summary> | ||
| 28 | /// <param name="pArgs">Pointer to BOOTSTRAPPER_CREATE_ARGS struct.</param> | ||
| 29 | /// <param name="pResults">Pointer to BOOTSTRAPPER_CREATE_RESULTS struct.</param> | ||
| 30 | /// <exception cref="MissingAttributeException">The bootstrapper application assembly | ||
| 31 | /// does not define the <see cref="BootstrapperApplicationFactoryAttribute"/>.</exception> | ||
| 32 | public void Create(IntPtr pArgs, IntPtr pResults) | ||
| 33 | { | ||
| 34 | // Load the BA's IBootstrapperApplicationFactory. | ||
| 35 | var baFactoryType = BootstrapperApplicationFactory.GetBAFactoryTypeFromAssembly(this.baFactoryAssemblyName, this.baFactoryAssemblyPath); | ||
| 36 | var baFactory = Activator.CreateInstance(baFactoryType); | ||
| 37 | if (null == baFactory) | ||
| 38 | { | ||
| 39 | throw new InvalidBootstrapperApplicationFactoryException(); | ||
| 40 | } | ||
| 41 | |||
| 42 | var createMethod = baFactoryType.GetMethod(nameof(Create), new[] { typeof(IntPtr), typeof(IntPtr) }); | ||
| 43 | if (null == createMethod) | ||
| 44 | { | ||
| 45 | throw new InvalidBootstrapperApplicationFactoryException(); | ||
| 46 | } | ||
| 47 | createMethod.Invoke(baFactory, new object[] { pArgs, pResults }); | ||
| 48 | } | ||
| 49 | |||
| 50 | /// <summary> | ||
| 51 | /// Locates the <see cref="BootstrapperApplicationFactoryAttribute"/> and returns the specified type. | ||
| 52 | /// </summary> | ||
| 53 | /// <param name="assemblyName">The assembly that defines the IBootstrapperApplicationFactory implementation.</param> | ||
| 54 | /// <returns>The bootstrapper application factory <see cref="Type"/>.</returns> | ||
| 55 | private static Type GetBAFactoryTypeFromAssembly(string assemblyName, string assemblyPath) | ||
| 56 | { | ||
| 57 | // The default ALC shouldn't need help loading the assembly, since the host should have provided the deps.json | ||
| 58 | // when starting the runtime. But it doesn't hurt so keep this in case an isolated ALC is ever needed. | ||
| 59 | var alc = new DnchostAssemblyLoadContext(assemblyPath, false); | ||
| 60 | var asm = alc.LoadFromAssemblyName(new AssemblyName(assemblyName)); | ||
| 61 | |||
| 62 | var attr = asm.GetCustomAttributes() | ||
| 63 | .Where(a => a.GetType().FullName == "WixToolset.Mba.Core.BootstrapperApplicationFactoryAttribute") | ||
| 64 | .SingleOrDefault(); | ||
| 65 | |||
| 66 | if (null == attr) | ||
| 67 | { | ||
| 68 | throw new MissingAttributeException(); | ||
| 69 | } | ||
| 70 | |||
| 71 | var baFactoryTypeProperty = attr.GetType().GetProperty("BootstrapperApplicationFactoryType", typeof(Type)); | ||
| 72 | if (baFactoryTypeProperty == null || baFactoryTypeProperty.GetMethod == null) | ||
| 73 | { | ||
| 74 | throw new MissingAttributeException(); | ||
| 75 | } | ||
| 76 | |||
| 77 | var baFactoryType = (Type)baFactoryTypeProperty.GetMethod.Invoke(attr, null); | ||
| 78 | return baFactoryType; | ||
| 79 | } | ||
| 80 | |||
| 81 | // Entry point for the DNC host. | ||
| 82 | public static IBootstrapperApplicationFactory CreateBAFactory([MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyName, [MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyPath) | ||
| 83 | { | ||
| 84 | return new BootstrapperApplicationFactory(baFactoryAssemblyName, baFactoryAssemblyPath); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
