diff --git a/FoundationDB.Client/Native/FdbNative.cs b/FoundationDB.Client/Native/FdbNative.cs
index 460032f0f..bf4adbc06 100644
--- a/FoundationDB.Client/Native/FdbNative.cs
+++ b/FoundationDB.Client/Native/FdbNative.cs
@@ -49,7 +49,7 @@ internal static unsafe class FdbNative
private const string FDB_C_DLL = "libfdb_c.so";
#else
/// Name of the C API dll used for P/Invoking
- private const string FDB_C_DLL = "fdb_c.dll";
+ private const string FDB_C_DLL = "fdb_c";
#endif
/// Handle on the native FDB C API library
@@ -235,42 +235,72 @@ public static extern void fdb_transaction_clear_range(
static FdbNative()
{
- // Impact of NativeLibPath:
- // - If null, don't preload the library, and let the CLR find the file using the default P/Invoke behavior
- // - If String.Empty, call win32 LoadLibrary("fdb_c.dll") and let the os find the file (using the standard OS behavior)
- // - Else, combine the path with "fdb_c.dll" and call LoadLibrary with the resulting (relative or absolute) path
+ var libraryPath = GetPreloadPath();
- var libraryPath = Fdb.Options.NativeLibPath;
- if (libraryPath != null)
+ if (libraryPath == null)
+ { // PInvoke will load
+ return;
+ }
+
+ try
{
- try
+ FdbCLib = UnmanagedLibrary.Load(libraryPath);
+ }
+ catch (Exception e)
+ {
+ if (FdbCLib != null) FdbCLib.Dispose();
+ FdbCLib = null;
+ if (e is BadImageFormatException && IntPtr.Size == 4)
{
- if (libraryPath.Length == 0)
- { // CLR will handle the search
- libraryPath = FDB_C_DLL;
- }
- else if (!libraryPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
- { // add the file name
- libraryPath = Path.Combine(Fdb.Options.NativeLibPath, FDB_C_DLL);
- }
-
- FdbCLib = UnmanagedLibrary.Load(libraryPath);
+ e = new InvalidOperationException("The native FDB client is 64-bit only, and cannot be loaded in a 32-bit process.", e);
}
- catch (Exception e)
+ else
{
- if (FdbCLib != null) FdbCLib.Dispose();
- FdbCLib = null;
- if (e is BadImageFormatException && IntPtr.Size == 4)
- {
- e = new InvalidOperationException("The native FDB client is 64-bit only, and cannot be loaded in a 32-bit process.", e);
- }
- else
- {
- e = new InvalidOperationException("An error occurred while loading the native FoundationDB library", e);
- }
- LibraryLoadError = ExceptionDispatchInfo.Capture(e);
+ e = new InvalidOperationException($"An error occurred while loading the native FoundationDB library: '{libraryPath}'.", e);
+ }
+ LibraryLoadError = ExceptionDispatchInfo.Capture(e);
+ }
+
+ }
+
+ private static string GetPreloadPath()
+ {
+ // we need to provide sensible defaults for loading the native library
+ // if this method returns null we'll let PInvoke deal
+ // otherwise - use explicit platform-specific dll loading
+ var libraryPath = Fdb.Options.NativeLibPath;
+
+ // on non-windows, library loading by convention just works.
+ // unless override is provided, just let PInvoke do the work
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ if (string.IsNullOrEmpty(libraryPath))
+ {
+ return null;
}
+ // otherwise just use the provided path
+ return libraryPath;
+ }
+
+ // Impact of NativeLibPath on windows:
+ // - If null, don't preload the library, and let the CLR find the file using the default P/Invoke behavior
+ // - If String.Empty, call win32 LoadLibrary(FDB_C_DLL + ".dll") and let the os find the file (using the standard OS behavior)
+ // - If path is folder, append the FDB_C_DLL
+ var winDllWithExtension = FDB_C_DLL + ".dll";
+ if (libraryPath == null)
+ {
+ return null;
+ }
+ if (libraryPath.Length == 0)
+ {
+ return winDllWithExtension;
+ }
+ var fileName = Path.GetFileName(libraryPath);
+ if (String.IsNullOrEmpty(fileName))
+ {
+ libraryPath = Path.Combine(libraryPath, winDllWithExtension);
}
+ return libraryPath;
}
private static void EnsureLibraryIsLoaded()
diff --git a/FoundationDB.Client/Native/UnmanagedLibrary.cs b/FoundationDB.Client/Native/UnmanagedLibrary.cs
index 62659bbdd..968045b0a 100644
--- a/FoundationDB.Client/Native/UnmanagedLibrary.cs
+++ b/FoundationDB.Client/Native/UnmanagedLibrary.cs
@@ -72,23 +72,24 @@ protected override bool ReleaseHandle()
[SuppressUnmanagedCodeSecurity]
private static class NativeMethods
{
-#if __MonoCS__
- const string KERNEL = "dl";
+ const string LIBDL = "dl";
+
- [DllImport(KERNEL)]
+ [DllImport(LIBDL)]
public static extern SafeLibraryHandle dlopen(string fileName, int flags);
- [DllImport(KERNEL, SetLastError = true)]
+
+ [DllImport(LIBDL, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern int dlclose(IntPtr hModule);
- public static SafeLibraryHandle LoadLibrary(string fileName)
- {
+#if __MonoCS__
+ public static SafeLibraryHandle LoadPlatformLibrary(string fileName)
+ {
return dlopen(fileName, 1);
-
}
- public static bool FreeLibrary(IntPtr hModule) { return dlclose(hModule) == 0; }
+ public static bool FreePlatformLibrary(IntPtr hModule) { return dlclose(hModule) == 0; }
#else
const string KERNEL = "kernel32";
@@ -100,6 +101,24 @@ public static SafeLibraryHandle LoadLibrary(string fileName)
[DllImport(KERNEL, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr hModule);
+
+ public static SafeLibraryHandle LoadPlatformLibrary(string fileName)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return LoadLibrary(fileName);
+ }
+ return dlopen(fileName, 1);
+ }
+
+ public static bool FreePlatformLibrary(IntPtr hModule)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return FreeLibrary(hModule);
+ }
+ return dlclose(hModule) == 0;
+ }
#endif
}
@@ -112,7 +131,7 @@ public static UnmanagedLibrary Load(string path)
{
if (path == null) throw new ArgumentNullException("path");
- var handle = NativeMethods.LoadLibrary(path);
+ var handle = NativeMethods.LoadPlatformLibrary(path);
if (handle == null || handle.IsInvalid)
{
var ex = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());