diff --git a/src/NodeApi/Runtime/NativeLibrary.cs b/src/NodeApi/Runtime/NativeLibrary.cs
index a7e59b4a..8820a7a5 100644
--- a/src/NodeApi/Runtime/NativeLibrary.cs
+++ b/src/NodeApi/Runtime/NativeLibrary.cs
@@ -4,6 +4,8 @@
#if !NET7_0_OR_GREATER
using System;
+using System.IO;
+using System.Reflection;
using System.Runtime.InteropServices;
#if !NETFRAMEWORK
using SysNativeLibrary = System.Runtime.InteropServices.NativeLibrary;
@@ -50,6 +52,25 @@ public static nint Load(string libraryName)
#endif
}
+ ///
+ /// Loads a native library using the high-level API.
+ ///
+ /// The name of the native library to be loaded.
+ /// The assembly loading the native library.
+ /// The search path.
+ /// The OS handle for the loaded native library.
+ public static nint Load(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
+ {
+#if NETFRAMEWORK
+ string libraryPath = FindLibrary(libraryName, assembly, searchPath)
+ ?? throw new DllNotFoundException($"Could not find library: {libraryName}");
+
+ return LoadLibrary(libraryPath);
+#else
+ return SysNativeLibrary.Load(libraryName, assembly, searchPath);
+#endif
+ }
+
///
/// Gets the address of an exported symbol.
///
@@ -75,6 +96,79 @@ public static bool TryGetExport(nint handle, string name, out nint procAddress)
#endif
}
+#if NETFRAMEWORK
+ ///
+ /// Searches various well-known paths for a library and returns the first result.
+ ///
+ /// Name of the library to search for.
+ /// Assembly to search relative from.
+ /// The search path.
+ /// Library path if found, otherwise false.
+ private static string? FindLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
+ {
+ if (Path.IsPathRooted(libraryName) && File.Exists(libraryName))
+ {
+ return Path.GetFullPath(libraryName);
+ }
+
+ string[] tryLibraryNames;
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ tryLibraryNames =
+ [
+ libraryName,
+ $"{libraryName}.dll"
+ ];
+ }
+ else
+ {
+ string libraryExtension = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
+ ? "dylib"
+ : "so";
+
+ tryLibraryNames =
+ [
+ libraryName,
+ $"lib{libraryName}",
+ $"{libraryName}.{libraryExtension}",
+ $"lib{libraryName}.{libraryExtension}"
+ ];
+ }
+
+ string?[] tryDirectories =
+ [
+ searchPath == null || (searchPath & DllImportSearchPath.AssemblyDirectory) > 0
+ ? Path.GetDirectoryName(assembly.Location)
+ : null,
+
+ searchPath == null || (searchPath & DllImportSearchPath.SafeDirectories) > 0
+ ? Environment.SystemDirectory
+ : null,
+ ];
+
+ foreach (string? tryDirectory in tryDirectories)
+ {
+ if (tryDirectory == null)
+ {
+ continue;
+ }
+
+ foreach (string tryLibraryName in tryLibraryNames)
+ {
+ string tryLibraryPath = Path.Combine(tryDirectory, tryLibraryName);
+
+ if (File.Exists(tryLibraryPath))
+ {
+ return tryLibraryPath;
+ }
+ }
+ }
+
+ return null;
+ }
+#endif
+
#pragma warning disable CA2101 // Specify marshaling for P/Invoke string arguments
[DllImport("kernel32")]
diff --git a/src/NodeApi/Runtime/NodejsPlatform.cs b/src/NodeApi/Runtime/NodejsPlatform.cs
index fe0c9b4a..c6d4e5b8 100644
--- a/src/NodeApi/Runtime/NodejsPlatform.cs
+++ b/src/NodeApi/Runtime/NodejsPlatform.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System;
+using System.Reflection;
using System.Runtime.InteropServices;
namespace Microsoft.JavaScript.NodeApi.Runtime;
@@ -25,23 +26,34 @@ public sealed class NodejsPlatform : IDisposable
///
/// Initializes the Node.js platform.
///
- /// Path to the `libnode` shared library, including extension.
+ ///
+ /// Name of the `libnode` shared library.
+ /// Has to be a full file path when using .NET Framework.
+ ///
/// Optional platform arguments.
/// A Node.js platform instance has already been
/// loaded in the current process.
public NodejsPlatform(
- string libnodePath,
+ string libnode,
string[]? args = null)
{
- if (string.IsNullOrEmpty(libnodePath)) throw new ArgumentNullException(nameof(libnodePath));
-
if (Current != null)
{
throw new InvalidOperationException(
"Only one Node.js platform instance per process is allowed.");
}
- nint libnodeHandle = NativeLibrary.Load(libnodePath);
+ var entryAssembly = Assembly.GetAssembly(typeof(NodejsPlatform));
+
+ nint libnodeHandle =
+ entryAssembly != null
+ ? NativeLibrary.Load(
+ libnode,
+ entryAssembly!,
+ DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories
+ )
+ : NativeLibrary.Load(libnode);
+
Runtime = new NodejsRuntime(libnodeHandle);
Runtime.CreatePlatform(args, (error) => Console.WriteLine(error), out _platform)