-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathClrLoader.cs
More file actions
146 lines (130 loc) · 4.5 KB
/
ClrLoader.cs
File metadata and controls
146 lines (130 loc) · 4.5 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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using NXPorts.Attributes;
namespace ClrLoader
{
public static class ClrLoader
{
static bool _initialized = false;
static List<DomainData> _domains = new List<DomainData>();
private static string PtrToStringUtf8(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return null;
int len = 0;
while (Marshal.ReadByte(ptr, len) != 0)
len++;
byte[] bytes = new byte[len];
Marshal.Copy(ptr, bytes, 0, len);
return Encoding.UTF8.GetString(bytes);
}
[DllExport("pyclr_initialize", CallingConvention.Cdecl)]
public static void Initialize()
{
if (!_initialized)
{
_domains.Add(new DomainData(AppDomain.CurrentDomain));
_initialized = true;
}
}
private static string AssemblyDirectory
{
get
{
// This is needed in case the DLL was shadow-copied
// (Otherwise .Location would work)
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
[DllExport("pyclr_create_appdomain", CallingConvention.Cdecl)]
public static IntPtr CreateAppDomain(IntPtr namePtr, IntPtr configFilePtr)
{
string name = PtrToStringUtf8(namePtr);
string configFile = PtrToStringUtf8(configFilePtr);
Print($"Creating AppDomain {name} with {configFile}");
var clrLoaderDir = AssemblyDirectory;
if (!string.IsNullOrEmpty(name))
{
var setup = new AppDomainSetup
{
ApplicationBase = clrLoaderDir,
ConfigurationFile = configFile
};
Print($"Base: {clrLoaderDir}");
var domain = AppDomain.CreateDomain(name, null, setup);
Print($"Located domain {domain}");
var domainData = new DomainData(domain);
_domains.Add(domainData);
return new IntPtr(_domains.Count - 1);
}
else
{
return IntPtr.Zero;
}
}
[DllExport("pyclr_get_function", CallingConvention.Cdecl)]
public static IntPtr GetFunction(
IntPtr domain,
IntPtr assemblyPathPtr,
IntPtr typeNamePtr,
IntPtr functionPtr
)
{
try
{
string assemblyPath = PtrToStringUtf8(assemblyPathPtr);
string typeName = PtrToStringUtf8(typeNamePtr);
string function = PtrToStringUtf8(functionPtr);
var domainData = _domains[(int)domain];
Print($"Getting functor for function {function} of type {typeName} in assembly {assemblyPath}");
return domainData.GetFunctor(assemblyPath, typeName, function);
}
catch (Exception exc)
{
Print($"Exception in {nameof(GetFunction)}: {exc.GetType().Name} {exc.Message}\n{exc.StackTrace}");
return IntPtr.Zero;
}
}
[DllExport("pyclr_close_appdomain", CallingConvention.Cdecl)]
public static void CloseAppDomain(IntPtr domain)
{
if (domain != IntPtr.Zero)
{
try
{
var domainData = _domains[(int)domain];
domainData.Dispose();
}
catch (Exception exc)
{
Print($"Exception in {nameof(CloseAppDomain)}: {exc.GetType().Name} {exc.Message}\n{exc.StackTrace}");
}
}
}
[DllExport("pyclr_finalize", CallingConvention.Cdecl)]
public static void Close()
{
foreach (var domainData in _domains)
{
domainData.Dispose();
}
_domains.Clear();
_initialized = false;
}
#if DEBUG
internal static void Print(string s)
{
Console.WriteLine(s);
}
#else
internal static void Print(string s) { }
#endif
}
}