// 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;
delegate IBootstrapperApplicationFactory StaticEntryDelegate([MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyName, [MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyPath);
///
/// 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);
}
}
}