-
Notifications
You must be signed in to change notification settings - Fork 127
Expand file tree
/
Copy pathModule.cs
More file actions
107 lines (90 loc) · 4.38 KB
/
Copy pathModule.cs
File metadata and controls
107 lines (90 loc) · 4.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// TODO: consider embedding this as a resource into WinRT.Host.dll,
// to simplify deployment
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading;
using WindowsRuntime.InteropServices.Marshalling;
[assembly: global::System.Runtime.Versioning.SupportedOSPlatform("Windows")]
#pragma warning disable CSWINRT3001 // Type or member is obsolete
namespace WinRT.Host;
/// <summary>
/// Provides the activation factory entry point used by the native <c>WinRT.Host</c> shim to host managed Windows Runtime components.
/// </summary>
public static class Shim
{
private const int S_OK = 0;
private const int E_NOINTERFACE = unchecked((int)0x80004002);
private const int REGDB_E_READREGDB = unchecked((int)0x80040150);
private const int CLASS_E_CLASSNOTAVAILABLE = unchecked((int)0x80040111);
/// <summary>
/// Delegate matching the native signature used to retrieve an activation factory from a hosted component.
/// </summary>
public unsafe delegate int GetActivationFactoryDelegate(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory);
private unsafe delegate void* ManagedExportsGetActivationFactoryDelegate(ReadOnlySpan<char> activatableClassId);
private static HashSet<string> _InitializedResolvers;
/// <summary>
/// Retrieves the activation factory for a runtime class from the specified target assembly, loading it into the default load context.
/// </summary>
public static unsafe int GetActivationFactory(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory)
{
*activationFactory = IntPtr.Zero;
string targetAssembly = HStringMarshaller.ConvertToManaged((void*)hstrTargetAssembly);
string runtimeClassId = HStringMarshaller.ConvertToManaged((void*)hstrRuntimeClassId);
try
{
Assembly assembly = LoadInDefaultContext(targetAssembly);
// ABI.<ModuleName>.ManagedExports.GetActivationFactory(ReadOnlySpan<char>) -> void*
string moduleName = Path.GetFileNameWithoutExtension(targetAssembly);
Type managedExportsType = assembly.GetType($"ABI.{moduleName}.ManagedExports");
if (managedExportsType == null)
{
return REGDB_E_READREGDB;
}
MethodInfo GetActivationFactory = managedExportsType.GetMethod("GetActivationFactory", [typeof(ReadOnlySpan<char>)]);
if (GetActivationFactory == null)
{
return REGDB_E_READREGDB;
}
// ReadOnlySpan<char> is a ref struct and can't be used with MethodInfo.Invoke.
// Use a delegate to call the method directly.
ManagedExportsGetActivationFactoryDelegate del = GetActivationFactory.CreateDelegate<ManagedExportsGetActivationFactoryDelegate>();
void* factory = del(runtimeClassId.AsSpan());
if (factory == null)
{
return CLASS_E_CLASSNOTAVAILABLE;
}
*activationFactory = (IntPtr)factory;
return S_OK;
}
catch (Exception e)
{
return RestrictedErrorInfoExceptionMarshaller.ConvertToUnmanaged(e);
}
}
private static Assembly LoadInDefaultContext(string targetAssembly)
{
if (_InitializedResolvers == null)
{
_ = Interlocked.CompareExchange(ref _InitializedResolvers, new HashSet<string>(StringComparer.OrdinalIgnoreCase), null);
}
lock (_InitializedResolvers)
{
if (!_InitializedResolvers.Contains(targetAssembly))
{
AssemblyDependencyResolver resolver = new(targetAssembly);
AssemblyLoadContext.Default.Resolving += (assemblyLoadContext, assemblyName) =>
{
string assemblyPath = resolver.ResolveAssemblyToPath(assemblyName);
return assemblyPath != null ? assemblyLoadContext.LoadFromAssemblyPath(assemblyPath) : null;
};
_ = _InitializedResolvers.Add(targetAssembly);
}
}
return AssemblyLoadContext.Default.LoadFromAssemblyPath(targetAssembly);
}
}