1
1
namespace HexaGen . Runtime
2
2
{
3
3
using System ;
4
+ using System . Collections ;
5
+ using System . Diagnostics ;
6
+ using System . Diagnostics . CodeAnalysis ;
4
7
using System . Reflection ;
8
+ using System . Runtime . CompilerServices ;
5
9
using System . Runtime . InteropServices ;
6
10
7
11
#if ! NET5_0_OR_GREATER
@@ -30,12 +34,21 @@ public enum TargetPlatform
30
34
Any = FreeBSD | Linux | OSX | Windows | Android | IOS | Tizen | ChromeOS | WebAssembly | Solaris | WatchOS | TVO
31
35
}
32
36
33
- public delegate void ResolvePathHandler ( string libraryName , out string ? pathToLibrary ) ;
37
+ public delegate bool ResolvePathHandler ( string libraryName , out string ? pathToLibrary ) ;
34
38
35
- public delegate void LibraryNameInterceptor ( ref string libraryName ) ;
39
+ public delegate bool LibraryNameInterceptor ( ref string libraryName ) ;
40
+
41
+ public delegate bool LibraryLoadInterceptor ( string libraryName , out nint pointer ) ;
42
+
43
+ public delegate bool NativeContextInterceptor ( string libraryName , out INativeContext ? context ) ;
36
44
37
45
public static class LibraryLoader
38
46
{
47
+ private static readonly EventHandlerList < ResolvePathHandler > resolvePathHandlers = [ ] ;
48
+ private static readonly EventHandlerList < LibraryNameInterceptor > libraryNameInterceptors = [ ] ;
49
+ private static readonly EventHandlerList < LibraryLoadInterceptor > libraryLoadInterceptors = [ ] ;
50
+ private static readonly EventHandlerList < NativeContextInterceptor > nativeContextInterceptors = [ ] ;
51
+
39
52
public static OSPlatform FreeBSD { get ; } = OSPlatform . Create ( "FREEBSD" ) ;
40
53
41
54
public static OSPlatform Linux { get ; } = OSPlatform . Create ( "LINUX" ) ;
@@ -62,9 +75,13 @@ public static class LibraryLoader
62
75
63
76
public static List < string > CustomLoadFolders { get ; } = [ ] ;
64
77
65
- public static ResolvePathHandler ? ResolvePath ;
78
+ public static event ResolvePathHandler ResolvePath { add => resolvePathHandlers . Add ( value ) ; remove => resolvePathHandlers . Remove ( value ) ; }
79
+
80
+ public static event LibraryNameInterceptor InterceptLibraryName { add => libraryNameInterceptors . Add ( value ) ; remove => libraryNameInterceptors . Remove ( value ) ; }
81
+
82
+ public static event LibraryLoadInterceptor InterceptLibraryLoad { add => libraryLoadInterceptors . Add ( value ) ; remove => libraryLoadInterceptors . Remove ( value ) ; }
66
83
67
- public static LibraryNameInterceptor ? InterceptLibraryName ;
84
+ public static event NativeContextInterceptor InterceptNativeContext { add => nativeContextInterceptors . Add ( value ) ; remove => nativeContextInterceptors . Remove ( value ) ; }
68
85
69
86
public static string GetExtension ( )
70
87
{
@@ -126,11 +143,62 @@ public static string GetExtension()
126
143
127
144
public delegate string LibraryExtensionCallback ( ) ;
128
145
129
- public static nint LoadLibrary ( LibraryNameCallback libraryNameCallback , LibraryExtensionCallback ? libraryExtensionCallback )
146
+ public static void LoadFromMainModule ( string targetLibraryName )
147
+ {
148
+ LoadFrom ( targetLibraryName , Process . GetCurrentProcess ( ) . MainModule ! . BaseAddress ) ;
149
+ }
150
+
151
+ public static void LoadFrom ( string targetLibraryName , nint address )
152
+ {
153
+ bool Callback ( string libraryName , out nint pointer )
154
+ {
155
+ if ( libraryName == targetLibraryName )
156
+ {
157
+ pointer = address ;
158
+ return true ;
159
+ }
160
+
161
+ pointer = 0 ;
162
+ return false ;
163
+ }
164
+
165
+ libraryLoadInterceptors . Add ( Callback ) ;
166
+ }
167
+
168
+ public static INativeContext LoadLibraryEx ( LibraryNameCallback libraryNameCallback , LibraryExtensionCallback ? libraryExtensionCallback )
169
+ {
170
+ var libraryName = libraryNameCallback ( ) ;
171
+
172
+ foreach ( var callback in nativeContextInterceptors )
173
+ {
174
+ if ( callback ( libraryName , out var context ) )
175
+ {
176
+ return context ?? throw new InvalidOperationException ( "'context' cannot be null when returning true." ) ;
177
+ }
178
+ }
179
+
180
+ return new NativeLibraryContext ( LoadLibrary ( libraryNameCallback , libraryExtensionCallback ) ) ;
181
+ }
182
+
183
+ public static nint LoadLibrary ( LibraryNameCallback libraryNameCallback , LibraryExtensionCallback ? libraryExtensionCallback , [ CallerMemberName ] string ? name = "" )
130
184
{
131
185
var libraryName = libraryNameCallback ( ) ;
132
186
133
- InterceptLibraryName ? . Invoke ( ref libraryName ) ;
187
+ foreach ( var callback in libraryNameInterceptors )
188
+ {
189
+ if ( callback ( ref libraryName ) )
190
+ {
191
+ break ;
192
+ }
193
+ }
194
+
195
+ foreach ( var callback in libraryLoadInterceptors )
196
+ {
197
+ if ( callback ( libraryName , out nint pointer ) )
198
+ {
199
+ return pointer ;
200
+ }
201
+ }
134
202
135
203
var extension = libraryExtensionCallback != null ? libraryExtensionCallback ( ) : GetExtension ( ) ;
136
204
@@ -143,9 +211,7 @@ public static nint LoadLibrary(LibraryNameCallback libraryNameCallback, LibraryE
143
211
var architecture = GetArchitecture ( ) ;
144
212
var libraryPath = GetNativeAssemblyPath ( osPlatform , architecture , libraryName ) ;
145
213
146
- nint handle ;
147
-
148
- handle = NativeLibrary . Load ( libraryPath ) ;
214
+ nint handle = NativeLibrary . Load ( libraryPath ) ;
149
215
150
216
if ( handle == IntPtr . Zero )
151
217
{
@@ -157,10 +223,12 @@ public static nint LoadLibrary(LibraryNameCallback libraryNameCallback, LibraryE
157
223
158
224
private static string GetNativeAssemblyPath ( string osPlatform , string architecture , string libraryName )
159
225
{
160
- if ( ResolvePath != null )
226
+ foreach ( var callback in resolvePathHandlers )
161
227
{
162
- ResolvePath . Invoke ( libraryName , out var pathToLibrary ) ;
163
- if ( pathToLibrary != null ) return pathToLibrary ;
228
+ if ( callback ( libraryName , out var pathToLibrary ) )
229
+ {
230
+ return pathToLibrary ?? throw new InvalidOperationException ( "'pathToLibrary' cannot be null when returning true." ) ;
231
+ }
164
232
}
165
233
166
234
#if ANDROID
0 commit comments