public static Delegate LoadFunc(INativeLibImporter importer, IntPtr libraryHandle, string entryPoint, Type delegateType) { IntPtr procAddress = importer.GetProcAddress(libraryHandle, entryPoint); if (procAddress == IntPtr.Zero) { throw new EntryPointNotFoundException(string.Format("Unable to get address of {0} ({1})", entryPoint, delegateType)); } return(Marshal.GetDelegateForFunctionPointer(procAddress, delegateType)); }
public static T LoadFunc <T>(INativeLibImporter importer, IntPtr libraryHandle, string entryPoint) { IntPtr procAddress = importer.GetProcAddress(libraryHandle, entryPoint); if (procAddress == IntPtr.Zero) { throw new NativeLoadException(string.Format("Unable to get address of {0} ({1})", entryPoint, typeof(T)), null); } return(CurrentFramework.GetDelegateForFunctionPointer <T>(procAddress)); }
static object GetDelegate(INativeLibImporter importer, IntPtr lib, string entryPoint, Type delegateType) { IntPtr procAddress = importer.GetProcAddress(lib, entryPoint); if (procAddress == IntPtr.Zero) { return(null); } var method = typeof(CurrentFramework).GetTypeInfo().GetMethod(nameof(CurrentFramework.GetDelegateForFunctionPointer)).MakeGenericMethod(delegateType); return(method.Invoke(null, new object[] { procAddress })); }
static object GetDelegate(INativeLibImporter importer, IntPtr lib, string entryPoint, Type delegateType) { IntPtr procAddress = importer.GetProcAddress(lib, entryPoint); if (procAddress == IntPtr.Zero) { var invokeMethod = delegateType.GetTypeInfo().GetMethod("Invoke"); var parameters = invokeMethod.GetParameters().Select(p => Expression.Parameter(p.ParameterType)).ToArray(); var returnType = invokeMethod.ReturnType; var errorMessage = string.Format("Unable to get address of {0} ({1})", entryPoint, delegateType); Action throwAction = () => throw new NativeLoadException(errorMessage, null); var callThrowExpr = Expression.Constant(throwAction, typeof(Action)); var defaultExpr = Expression.Default(returnType); var block = Expression.Block(returnType, Expression.Invoke(callThrowExpr), defaultExpr); var lambda = Expression.Lambda(delegateType, block, parameters); return(lambda.Compile()); } var method = typeof(CurrentFramework).GetTypeInfo().GetMethod(nameof(CurrentFramework.GetDelegateForFunctionPointer)).MakeGenericMethod(delegateType); return(method.Invoke(null, new object[] { procAddress })); }
public static T Import <T>(INativeLibImporter importer, string libName, string version, bool suppressUnload) where T : class { var subdir = GetArchName(RuntimeInformation.ProcessArchitecture); var assemblyName = new AssemblyName("DynamicLink"); var assemblyBuilder = CurrentFramework.DefineDynamicAssembly(assemblyName, System.Reflection.Emit.AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynLinkModule"); string typeName = typeof(T).Name + "_impl"; var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, typeof(T)); FieldBuilder field_importer = typeBuilder.DefineField("importer", typeof(INativeLibImporter), FieldAttributes.Private | FieldAttributes.InitOnly); FieldBuilder field_libraryHandle = typeBuilder.DefineField("libraryHandle", typeof(IntPtr), FieldAttributes.Private | FieldAttributes.InitOnly); var methods = typeof(T).GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(m => m.IsAbstract && !m.IsGenericMethod).ToArray(); // Define delegate types for each of the method signatures var delegateMap = new Dictionary <string, Type>(); foreach (var method in methods) { var sig = GetMethodSig(method); if (delegateMap.ContainsKey(sig)) { continue; } var delegateTypeInfo = CreateDelegateType(moduleBuilder, method); delegateMap.Add(sig, delegateTypeInfo.AsType()); } // Define one field for each method to hold a delegate var delegates = methods.Select(m => new { MethodInfo = m, DelegateType = delegateMap[GetMethodSig(m)], }).ToArray(); var fields = delegates.Select((d, i) => typeBuilder.DefineField($"{d.MethodInfo.Name}_func_{i}", d.DelegateType, FieldAttributes.Private)).ToArray(); // Create the constructor which will initialize the importer and library handle // and also use the importer to populate each of the delegate fields ConstructorBuilder constructor = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(INativeLibImporter), typeof(IntPtr) }); { var baseConstructor = typeof(T).GetTypeInfo().GetConstructors().Where(con => con.GetParameters().Length == 0).First(); ILGenerator il = constructor.GetILGenerator(); // Call base constructor il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Call, baseConstructor); // Store importer field il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_1); // importer il.Emit(OpCodes.Stfld, field_importer); // Load and store library handle il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_2); // library handle il.Emit(OpCodes.Stfld, field_libraryHandle); var getDelegateMethod = typeof(INativeLibImporter).GetTypeInfo().GetMethod("GetDelegate"); // Initialize each delegate field for (int i = 0; i < fields.Length; i++) { var delegateType = delegates[i].DelegateType; il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_1); // importer il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_libraryHandle); il.Emit(OpCodes.Ldstr, delegates[i].MethodInfo.Name); // use method name from original class as entry point il.Emit(OpCodes.Ldtoken, delegateType); // the delegate type il.Emit(OpCodes.Call, typeof(System.Type).GetTypeInfo().GetMethod("GetTypeFromHandle")); // typeof() il.Emit(OpCodes.Callvirt, getDelegateMethod); // importer.GetDelegate() il.Emit(OpCodes.Isinst, delegateType); // as <delegate type> il.Emit(OpCodes.Stfld, fields[i]); } // End of constructor il.Emit(OpCodes.Ret); } // Create destructor var destructor = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig); { var baseDestructor = typeof(T).GetTypeInfo().GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); var il = destructor.GetILGenerator(); var end = il.DefineLabel(); il.BeginExceptionBlock(); if (!suppressUnload) { il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_importer); // .importer il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_libraryHandle); // .libraryHandle il.Emit(OpCodes.Callvirt, typeof(INativeLibImporter).GetTypeInfo().GetMethod("FreeLibrary")); // INativeLibImporter::FreeLibrary() } //il.Emit(OpCodes.Leave, end); il.BeginFinallyBlock(); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Call, baseDestructor); // object::Finalize() //il.Emit(OpCodes.Endfinally); il.EndExceptionBlock(); il.MarkLabel(end); il.Emit(OpCodes.Ret); } // Now override each method from the base class for (int i = 0; i < fields.Length; i++) { var baseMethod = delegates[i].MethodInfo; var args = baseMethod.GetParameters(); var omethod = typeBuilder.DefineMethod( baseMethod.Name, (baseMethod.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.NewSlot)) | MethodAttributes.Virtual, baseMethod.CallingConvention, baseMethod.ReturnType, args.Select(arg => arg.ParameterType).ToArray() ); var il = omethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, fields[i]); // {field} if (args.Length >= 1) { il.Emit(OpCodes.Ldarg_1); } if (args.Length >= 2) { il.Emit(OpCodes.Ldarg_2); } if (args.Length >= 3) { il.Emit(OpCodes.Ldarg_3); } for (short argNum = 4; argNum <= args.Length; argNum++) { il.Emit(OpCodes.Ldarg_S, argNum); } il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Callvirt, delegates[i].DelegateType.GetTypeInfo().GetMethod("Invoke")); il.Emit(OpCodes.Ret); } var type = typeBuilder.CreateTypeInfo(); var versionParts = version.Split('.'); var names = versionParts.Select((p, i) => libName + "-" + string.Join(".", versionParts.Take(i + 1))) .Reverse() .Concat(Enumerable.Repeat(libName, 1)); // try to load locally var paths = new[] { Path.Combine("native", subdir), "native", subdir, "", }; // If the RocksDbNative package is referenced, then dynamically load it here so that it can tell us where the native libraries are string nativeCodeBase = null; try { var nativeLibName = new AssemblyName("RocksDbNative"); var native = Assembly.Load(nativeLibName); var nativePkgClass = native.GetTypes().First(t => t.FullName == "RocksDbSharp.NativePackage"); var getCodeBaseMethod = nativePkgClass.GetTypeInfo().GetMethod("GetCodeBase"); var getCodeBase = getCodeBaseMethod.CreateDelegate <Func <string> >(); nativeCodeBase = getCodeBase(); } catch (Exception) { } var basePaths = new string[] { nativeCodeBase, Path.GetDirectoryName(UriToPath(Transitional.CurrentFramework.GetBaseDirectory())), Path.GetDirectoryName(UriToPath(Assembly.GetEntryAssembly()?.CodeBase)), Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location), Path.GetDirectoryName(UriToPath(typeof(PosixImporter).GetTypeInfo().Assembly.CodeBase)), Path.GetDirectoryName(typeof(PosixImporter).GetTypeInfo().Assembly.Location), }; var search = basePaths .Where(p => p != null) .Distinct() .SelectMany(basePath => paths.SelectMany(path => names.Select(n => Path.Combine(basePath, path, importer.Translate(n)))) .Concat(names.Select(n => importer.Translate(n))) ) .Select(path => new SearchPath { Path = path }) .ToArray(); foreach (var spec in search) { var construct = type.GetConstructor(new Type[] { typeof(INativeLibImporter), typeof(IntPtr) }); IntPtr lib = IntPtr.Zero; try { lib = importer.LoadLibrary(spec.Path); if (lib == IntPtr.Zero) { throw new NativeLoadException("LoadLibrary returned 0", null); } } catch (TargetInvocationException tie) { spec.Error = tie.InnerException; continue; } catch (Exception e) { spec.Error = e; continue; } var obj = construct.Invoke(new object[] { importer, lib }); var t = obj as T; return(t); } throw new NativeLoadException("Unable to locate rocksdb native library, either install it, or use RocksDbNative nuget package\nSearched:\n" + string.Join("\n", search.Select(s => $"{s.Path}: ({s.Error.GetType().Name}) {s.Error.Message}")), null); }
public static T Import <T>(INativeLibImporter importer, string name, bool suppressUnload) where T : class { var assemblyName = new AssemblyName("DynamicLink"); var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave); var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynLinkModule", "dynamic.dll"); string typeName = typeof(T).Name + "_impl"; var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, typeof(T)); FieldBuilder field_importer = typeBuilder.DefineField("importer", typeof(INativeLibImporter), FieldAttributes.Private | FieldAttributes.InitOnly); FieldBuilder field_libraryHandle = typeBuilder.DefineField("libraryHandle", typeof(IntPtr), FieldAttributes.Private | FieldAttributes.InitOnly); var methods = typeof(T).GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(m => m.IsAbstract && !m.IsGenericMethod).ToArray(); // Define delegate types for each of the method signatures var delegateMap = new Dictionary <string, Type>(); foreach (var method in methods) { var sig = GetMethodSig(method); if (delegateMap.ContainsKey(sig)) { continue; } var delegateType = CreateDelegateType(moduleBuilder, method); delegateMap.Add(sig, delegateType); } // Define one field for each method to hold a delegate var delegates = methods.Select(m => new { MethodInfo = m, DelegateType = delegateMap[GetMethodSig(m)], }).ToArray(); var fields = delegates.Select(d => typeBuilder.DefineField(d.MethodInfo.Name + "_func", d.DelegateType, FieldAttributes.Private)).ToArray(); // Create the constructor which will initialize the importer and library handle // and also use the importer to populate each of the delegate fields ConstructorBuilder constructor = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(INativeLibImporter), typeof(string) }); { var baseConstructor = typeof(T).GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null); ILGenerator il = constructor.GetILGenerator(); // Call base constructor il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Call, baseConstructor); // Store importer field il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_1); // importer il.Emit(OpCodes.Stfld, field_importer); // Load and store library handle il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_1); // importer il.Emit(OpCodes.Ldarg_2); // name il.Emit(OpCodes.Callvirt, typeof(INativeLibImporter).GetMethod("LoadLibrary")); il.Emit(OpCodes.Stfld, field_libraryHandle); // Initialize each delegate field for (int i = 0; i < fields.Length; i++) { il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldarg_1); // importer il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_libraryHandle); il.Emit(OpCodes.Ldstr, delegates[i].MethodInfo.Name); // use method name from original class as entry point il.Emit(OpCodes.Ldtoken, delegates[i].DelegateType); // the delegate type il.Emit(OpCodes.Call, typeof(System.Type).GetMethod("GetTypeFromHandle")); // typeof() il.Emit(OpCodes.Call, typeof(U).GetMethod("LoadFunc")); // U.LoadFunc() il.Emit(OpCodes.Isinst, delegates[i].DelegateType); // as <delegate type> il.Emit(OpCodes.Stfld, fields[i]); } // End of constructor il.Emit(OpCodes.Ret); } // Create destructor var destructor = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig); { var baseDestructor = typeof(T).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); var il = destructor.GetILGenerator(); var end = il.DefineLabel(); il.BeginExceptionBlock(); if (!suppressUnload) { il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_importer); // .importer il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field_libraryHandle); // .libraryHandle il.Emit(OpCodes.Callvirt, typeof(INativeLibImporter).GetMethod("FreeLibrary")); // INativeLibImporter::FreeLibrary() } //il.Emit(OpCodes.Leave, end); il.BeginFinallyBlock(); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Call, baseDestructor); // object::Finalize() //il.Emit(OpCodes.Endfinally); il.EndExceptionBlock(); il.MarkLabel(end); il.Emit(OpCodes.Ret); } // Now override each method from the base class for (int i = 0; i < fields.Length; i++) { var baseMethod = delegates[i].MethodInfo; var args = baseMethod.GetParameters(); var omethod = typeBuilder.DefineMethod( baseMethod.Name, (baseMethod.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.NewSlot)) | MethodAttributes.Virtual, baseMethod.CallingConvention, baseMethod.ReturnType, args.Select(arg => arg.ParameterType).ToArray() ); var il = omethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, fields[i]); // {field} if (args.Length >= 1) { il.Emit(OpCodes.Ldarg_1); } if (args.Length >= 2) { il.Emit(OpCodes.Ldarg_2); } if (args.Length >= 3) { il.Emit(OpCodes.Ldarg_3); } for (short argNum = 4; argNum <= args.Length; argNum++) { il.Emit(OpCodes.Ldarg_S, argNum); } il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Callvirt, delegates[i].DelegateType.GetMethod("Invoke")); il.Emit(OpCodes.Ret); } var type = typeBuilder.CreateType(); //assemblyBuilder.Save("dynamic.dll"); var construct = type.GetConstructor(new Type[] { typeof(INativeLibImporter), typeof(string) }); var obj = construct.Invoke(new object[] { importer, name }); var t = obj as T; return(t); }