aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs')
-rw-r--r--src/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs87
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
3namespace 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}