Created
October 27, 2023 09:48
-
-
Save Aurumaker72/72b5fcc4b43cbd2f2e3cc5b91465d610 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Runtime.InteropServices; | |
| namespace M64RPFW.Models.Helpers; | |
| /// <summary> | |
| /// Marks a pseudo-<see cref="DllImportAttribute"/>ed function resolved at runtime. | |
| /// | |
| /// <para> | |
| /// To register correctly, a <c>RuntimeDllImport</c>ed delegate must either | |
| /// set the <see cref="Name"/> property or start with a capital <c>D</c>. | |
| /// </para> | |
| /// </summary> | |
| [AttributeUsage(AttributeTargets.Delegate)] | |
| public class RuntimeDllImportAttribute : Attribute | |
| { | |
| /// <summary> | |
| /// The name of the function to import. If it is not set and the | |
| /// delegate's name begins with a capital <c>D</c>, then an automatic | |
| /// name will be generated by removing the first character. | |
| /// </summary> | |
| public string? Name { get; init; } | |
| } | |
| public static class NativeLibHelper | |
| { | |
| /// <summary> | |
| /// Tries to get a function from a library. | |
| /// </summary> | |
| /// <param name="lib">The library</param> | |
| /// <param name="name">The name of the function</param> | |
| /// <typeparam name="T">A delegate type to call the function</typeparam> | |
| /// <exception cref="EntryPointNotFoundException">If the function can't be found.</exception> | |
| /// <returns></returns> | |
| public static T? GetFunction<T>(IntPtr lib, string name) | |
| { | |
| IntPtr res = NativeLibrary.GetExport(lib, name); | |
| return (res == IntPtr.Zero)? default : Marshal.GetDelegateForFunctionPointer<T>(res); | |
| } | |
| /// <summary> | |
| /// Resolve a delegate tagged with <see cref="RuntimeDllImportAttribute"/>. | |
| /// </summary> | |
| /// <param name="lib">the library to resolve symbols from</param> | |
| /// <param name="del">the delegate to set</param> | |
| /// <typeparam name="T">the delegate to resolve to</typeparam> | |
| /// <returns>the delegate</returns> | |
| /// <exception cref="ArgumentException">If the delegate type is not tagged correctly</exception> | |
| /// <seealso cref="RuntimeDllImportAttribute"/> | |
| public static void ResolveDelegate<T>(IntPtr lib, out T del) where T : Delegate | |
| { | |
| Attribute[] attrs = Attribute.GetCustomAttributes(typeof(T)); | |
| var rtDllImport = (RuntimeDllImportAttribute?) | |
| attrs.FirstOrDefault(a => a is RuntimeDllImportAttribute, null); | |
| if (rtDllImport is null) | |
| { | |
| throw new ArgumentException( | |
| $"Type T ({typeof(T).FullName}) is not tagged with {typeof(RuntimeDllImportAttribute).FullName}"); | |
| } | |
| string symbol; | |
| if (rtDllImport.Name is null) | |
| { | |
| string name = typeof(T).Name; | |
| if (name[0] != 'D') | |
| { | |
| throw new ArgumentException("Type does not match automatic delegate typename"); | |
| } | |
| symbol = name.Substring(1); | |
| } | |
| else | |
| { | |
| symbol = rtDllImport.Name; | |
| } | |
| T? val = GetFunction<T>(lib, symbol); | |
| if (val == null) | |
| throw new ApplicationException("Failed to load function"); | |
| del = val; | |
| } | |
| public static string AsDLL(string name) | |
| { | |
| return $"{name}{LibraryExtension}"; | |
| } | |
| private static string? _platformLibExtension; | |
| public static string LibraryExtension | |
| { | |
| get | |
| { | |
| if (_platformLibExtension != null) | |
| return _platformLibExtension; | |
| if (OperatingSystem.IsWindows()) | |
| return _platformLibExtension = ".dll"; | |
| if (OperatingSystem.IsLinux()) | |
| return _platformLibExtension = ".so"; | |
| throw new PlatformNotSupportedException("Only Windows and Linux are supported at the moment"); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment