После того, как Ник указал мне в сторону R.NET, я смог посмотреть, как они решили эту проблему.
Сначала они используют API Win32 для загрузки библиотеки (или эквивалент на других платформах):
#if MAC || LINUX
private static IntPtr LoadLibrary(string filename)
{
const int RTLD_LAZY = 0x1;
if (filename.StartsWith("/"))
{
return dlopen(filename, RTLD_LAZY);
}
string[] searchPaths = (System.Environment.GetEnvironmentVariable(LibraryPath, EnvironmentVariableTarget.Process) ?? "").Split(Path.PathSeparator);
foreach (string directory in searchPaths)
{
string path = Path.Combine(directory, filename);
if (File.Exists(path))
{
return dlopen(path, RTLD_LAZY);
}
}
return IntPtr.Zero;
}
[DllImport(DynamicLoadingLibraryName)]
private static extern IntPtr dlopen([MarshalAs(UnmanagedType.LPStr)] string filename, int flag);
#elif WINDOWS
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
Затем они используют функцию getProcAddress из kernel32.dll (или эквивалентную на других платформах), чтобы получить фактический адрес переменной:
#if MAC
[DllImport("libdl.dylib", EntryPoint = "dlsym")]
#elif LINUX
[DllImport("libdl.so", EntryPoint = "dlsym")]
#elif WINDOWS
[DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
#endif
private static extern IntPtr GetSymbolPointer(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string symbol);