|
1 | 1 | using System;
|
2 | 2 | using System.Collections.Generic;
|
3 | 3 | using System.Reflection;
|
| 4 | +using System.Runtime.InteropServices; |
4 | 5 |
|
5 | 6 | namespace ClrLoader
|
6 | 7 | {
|
7 | 8 | using static ClrLoader;
|
8 | 9 |
|
9 |
| - class DomainData : IDisposable |
| 10 | + public static class DomainSetup |
10 | 11 | {
|
11 | 12 | public delegate int EntryPoint(IntPtr buffer, int size);
|
| 13 | + public static void StoreFunctorFromDomainData() |
| 14 | + { |
| 15 | + var domain = AppDomain.CurrentDomain; |
| 16 | + var assemblyPath = (string)domain.GetData("_assemblyPath"); |
| 17 | + var typeName = (string)domain.GetData("_typeName"); |
| 18 | + var function = (string)domain.GetData("_function"); |
| 19 | + var functor = GetFunctor(domain, assemblyPath, typeName, function); |
| 20 | + domain.SetData("_thisFunctor", functor); |
| 21 | + } |
| 22 | + |
| 23 | + private static IntPtr GetFunctor(AppDomain domain, string assemblyPath, string typeName, string function) |
| 24 | + { |
| 25 | + var assemblyName = AssemblyName.GetAssemblyName(assemblyPath).Name; |
| 26 | + var assembly = domain.Load(AssemblyName.GetAssemblyName(assemblyPath)); |
| 27 | + var type = assembly.GetType(typeName, throwOnError: true); |
| 28 | + var deleg = Delegate.CreateDelegate(typeof(EntryPoint), type, function); |
| 29 | + IntPtr result = Marshal.GetFunctionPointerForDelegate(deleg); |
| 30 | + return result; |
| 31 | + } |
| 32 | + } |
12 | 33 |
|
| 34 | + class DomainData : IDisposable |
| 35 | + { |
13 | 36 | bool _disposed = false;
|
14 | 37 |
|
15 | 38 | public AppDomain Domain { get; }
|
16 |
| - public Dictionary<(string, string, string), EntryPoint> _delegates; |
| 39 | + public Dictionary<(string, string, string), IntPtr> _functors; |
| 40 | + public HashSet<string> _resolvedAssemblies; |
17 | 41 |
|
18 | 42 | public DomainData(AppDomain domain)
|
19 | 43 | {
|
20 | 44 | Domain = domain;
|
21 |
| - _delegates = new Dictionary<(string, string, string), EntryPoint>(); |
| 45 | + _functors = new Dictionary<(string, string, string), IntPtr>(); |
| 46 | + _resolvedAssemblies = new HashSet<string>(); |
22 | 47 | }
|
23 | 48 |
|
24 |
| - public EntryPoint GetEntryPoint(string assemblyPath, string typeName, string function) |
| 49 | + private void installResolver(string assemblyPath) |
| 50 | + { |
| 51 | + var assemblyName = AssemblyName.GetAssemblyName(assemblyPath).Name; |
| 52 | + if (_resolvedAssemblies.Contains(assemblyName)) |
| 53 | + return; |
| 54 | + _resolvedAssemblies.Add(assemblyName); |
| 55 | + |
| 56 | + AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => |
| 57 | + { |
| 58 | + if (args.Name.Contains(assemblyName)) |
| 59 | + return Assembly.LoadFrom(assemblyPath); |
| 60 | + return null; |
| 61 | + }; |
| 62 | + } |
| 63 | + |
| 64 | + public IntPtr GetFunctor(string assemblyPath, string typeName, string function) |
25 | 65 | {
|
26 | 66 | if (_disposed)
|
27 | 67 | throw new InvalidOperationException("Domain is already disposed");
|
28 | 68 |
|
29 |
| - var key = (assemblyPath, typeName, function); |
| 69 | + installResolver(assemblyPath); |
30 | 70 |
|
31 |
| - EntryPoint result; |
| 71 | + var key = (assemblyPath, typeName, function); |
32 | 72 |
|
33 |
| - if (!_delegates.TryGetValue(key, out result)) |
| 73 | + IntPtr result; |
| 74 | + if (!_functors.TryGetValue(key, out result)) |
34 | 75 | {
|
35 |
| - var assembly = Domain.Load(AssemblyName.GetAssemblyName(assemblyPath)); |
36 |
| - var type = assembly.GetType(typeName, throwOnError: true); |
| 76 | + Domain.SetData("_assemblyPath", assemblyPath); |
| 77 | + Domain.SetData("_typeName", typeName); |
| 78 | + Domain.SetData("_function", function); |
37 | 79 |
|
38 |
| - Print($"Loaded type {type}"); |
39 |
| - result = (EntryPoint)Delegate.CreateDelegate(typeof(EntryPoint), type, function); |
40 |
| - |
41 |
| - _delegates[key] = result; |
| 80 | + Domain.DoCallBack(new CrossAppDomainDelegate(DomainSetup.StoreFunctorFromDomainData)); |
| 81 | + result = (IntPtr)Domain.GetData("_thisFunctor"); |
| 82 | + _functors[key] = result; |
42 | 83 | }
|
43 |
| - |
44 | 84 | return result;
|
45 | 85 | }
|
46 | 86 |
|
47 | 87 | public void Dispose()
|
48 | 88 | {
|
49 | 89 | if (!_disposed)
|
50 | 90 | {
|
51 |
| - _delegates.Clear(); |
| 91 | + _functors.Clear(); |
52 | 92 |
|
53 | 93 | if (Domain != AppDomain.CurrentDomain)
|
54 | 94 | AppDomain.Unload(Domain);
|
|
0 commit comments