using System; using System.Runtime.InteropServices; namespace Efl { namespace Eo { ///Class to load functions pointers from a native module. /// ///This class has a platform-dependent implementation on whether it ///is compiled for Windows (using LoadLibrary/GetProcAddress) or Unix ///(dlopen/dlsym). public partial class FunctionInterop { ///Loads a function pointer from the given module. ///The name of the module containing the function. ///The name of the function to search for. ///A function pointer that can be used with delegates. public static IntPtr LoadFunctionPointer(string moduleName, string functionName) { NativeModule module = new NativeModule(moduleName); Eina.Log.Debug($"searching {module.Module} for {functionName}"); var s = FunctionInterop.dlsym(module.Module, functionName); Eina.Log.Debug($"searching {module.Module} for{functionName}, result {s}"); return s; } ///Loads a function pointer from the default module. ///The name of the function to search for. ///A function pointer that can be used with delegates. public static IntPtr LoadFunctionPointer(string functionName) { Eina.Log.Debug($"searching {null} for {functionName}"); var s = FunctionInterop.dlsym(IntPtr.Zero, functionName); Eina.Log.Debug($"searching {null} for {functionName}, result {s}"); return s; } } ///Wraps a native function in a portable manner. /// ///This is intended as a workaround DllImport limitations when switching between mono and dotnet. /// ///The parameter T must be a delegate. /// public class FunctionWrapper // NOTE: When supporting C# >=7.3, add a where T: System.Delegate? { private Lazy> loadResult; #pragma warning disable 0414 private NativeModule module; // so it doesn't get unloaded #pragma warning restore 0414 private static FunctionLoadResult LazyInitialization(NativeModule module, string functionName) { if (module.Module == IntPtr.Zero) { return new FunctionLoadResult(FunctionLoadResultKind.LibraryNotFound); } else { IntPtr funcptr = FunctionInterop.LoadFunctionPointer(module.Module, functionName); if (funcptr == IntPtr.Zero) { return new FunctionLoadResult(FunctionLoadResultKind.FunctionNotFound); } else { return new FunctionLoadResult(Marshal.GetDelegateForFunctionPointer(funcptr)); } } } ///Creates a wrapper for the given function of the given module. ///The name of the module containing the function. ///The name of the function to search for. public FunctionWrapper(string moduleName, string functionName) : this(new NativeModule(moduleName), functionName) { } ///Creates a wrapper for the given function of the given module. ///The module wrapper containing the function. ///The name of the function to search for. public FunctionWrapper(NativeModule module, string functionName) { this.module = module; loadResult = new Lazy> (() => { return LazyInitialization(module, functionName); }); } ///Retrieves the result of function load. ///The load result. public FunctionLoadResult Value { get { return loadResult.Value; } } } ///The outcome of the function load process. public enum FunctionLoadResultKind { ///Function was loaded successfully. Success, ///Library was not found. LibraryNotFound, ///Function symbol was not found in the given module. FunctionNotFound } ///Represents the result of loading a function pointer. public class FunctionLoadResult { ///The status of the load. public FunctionLoadResultKind Kind; private T _Delegate; ///The delegate wrapping the loaded function pointer. /// ///Throws InvalidOperationException if trying to access while not loaded. public T Delegate { get { if (_Delegate == null) { throw new InvalidOperationException($"Trying to get Delegate while not loaded. Load result: {Kind}"); } return _Delegate; } } ///Creates a new load result of the given kind. ///The outcome of the load process. public FunctionLoadResult(FunctionLoadResultKind kind) { this.Kind = kind; } ///Creates a new load result with the given delegate. ///The delegate wrapping the native function. public FunctionLoadResult(T Delegate) { this._Delegate = Delegate; this.Kind = FunctionLoadResultKind.Success; } } } }