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