Last active
October 3, 2024 12:31
-
-
Save kb10uy/37a0f0330a719e16c1323fdb8cbdef15 to your computer and use it in GitHub Desktop.
A generic script for UnityEditor that loads dynamic library *dynamically*. In other words, it can avoid the Unity's "never unread" restriction.
This file contains 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
/* | |
DynamicNativeLibrary.cs by kb10uy | |
This code is licensed under the CC0-1.0. | |
You should have received a copy of the CC0 legalcode along with this work. | |
If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. | |
*/ | |
using System; | |
using System.Runtime.InteropServices; | |
namespace KusakaFactory.Dylib | |
{ | |
public sealed class DynamicNativeLibrary : SafeHandle | |
{ | |
public override bool IsInvalid => handle == IntPtr.Zero; | |
private DynamicNativeLibrary(IntPtr moduleHandle) : base(IntPtr.Zero, true) | |
{ | |
SetHandle(moduleHandle); | |
} | |
protected override bool ReleaseHandle() | |
{ | |
return GenericClose(handle); | |
} | |
public static DynamicNativeLibrary Load(string libraryPath) | |
{ | |
var moduleHandle = GenericOpen(libraryPath); | |
if (moduleHandle == IntPtr.Zero) | |
{ | |
throw new ArgumentException($"failed to load dynamic library '{libraryPath}'"); | |
} | |
return new DynamicNativeLibrary(moduleHandle); | |
} | |
public TDelegate GetFunction<TDelegate>(string functionName) where TDelegate : Delegate | |
{ | |
var functionPointer = GenericSymbolAddress(handle, functionName); | |
if (functionPointer == IntPtr.Zero) | |
{ | |
throw new ArgumentException($"failed to get function address '{functionName}'"); | |
} | |
return Marshal.GetDelegateForFunctionPointer<TDelegate>(functionPointer); | |
} | |
#if UNITY_EDITOR_WIN | |
private static IntPtr GenericOpen(string filename) => NativeMethods.LoadLibrary(filename); | |
private static bool GenericClose(IntPtr handle) => NativeMethods.FreeLibrary(handle); | |
private static IntPtr GenericSymbolAddress(IntPtr handle, string symbol) => NativeMethods.GetProcAddress(handle, symbol); | |
#elif UNITY_EDITOR_LINUX || UNITY_EDITOR_OSX | |
private static IntPtr Open(string filename) => NativeMethods.dlopen(filename, NativeMethods.RTLD_LAZY); | |
private static bool Close(IntPtr handle) => NativeMethods.dlclose(handle) == 0; | |
private static IntPtr GetSymbolAddress(IntPtr handle, string symbol) => NativeMethods.dlsym(handle, symbol); | |
#endif | |
private static class NativeMethods | |
{ | |
#if UNITY_EDITOR_WIN | |
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] | |
public extern static IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPWStr)] string filename); | |
[DllImport("kernel32.dll")] | |
public extern static bool FreeLibrary(IntPtr handle); | |
[DllImport("kernel32.dll")] | |
public extern static IntPtr GetProcAddress(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string procName); | |
#elif UNITY_EDITOR_LINUX | |
const int RTLD_LAZY = 1; | |
[DllImport("libdl.so.2")] | |
public extern static IntPtr dlopen(string filename, int flags); | |
[DllImport("libdl.so.2")] | |
public extern static int dlclose(IntPtr handle); | |
[DllImport("libdl.so.2")] | |
public extern static IntPtr dlsym(IntPtr handle, string symbol); | |
#elif UNITY_EDITOR_OSX | |
const int RTLD_LAZY = 1; | |
[DllImport("libdl.dylib")] | |
public extern static IntPtr dlopen(string filename, int flags); | |
[DllImport("libdl.dylib")] | |
public extern static int dlclose(IntPtr handle); | |
[DllImport("libdl.dylib")] | |
public extern static IntPtr dlsym(IntPtr handle, string symbol); | |
#endif | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment