Beispiel #1
0
            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 }));
        }
Beispiel #4
0
        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 }));
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        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);
        }