Rhino 8 & .net 7 - loading native DLL's

We are ploughing through the upgrade of our codebase to .net 7.

Our plugin uses some Native C++ DLL’s which reside in \runtimes\win-x64\native\ - a subfolder from where our .rhp file is.
Unfortunately they are not resolved when our plugin loads.

If i copy our dll’s into C:\Program Files\Rhino 8\System\netcore\runtimes\win-x64\native then the dll’s are found and the plugin loads.

I assume that the root cause here is that we are using Rhino’s “runtime” of .net rather than our plugin. So our plugin is not in the search path

Is there a mechanism i can use to tell the runtime where to load the dll from? or add a path to the load system?

Any advice appreciated :slight_smile:

Dit it work before, or does it still work with .net4.8?
How are the native DLLs used in your plug-in? If with P/invoke, maybe you could set the relative path in the DllImport statement?

Also

1 Like

Thanks @menno yeah it works nicely with .net 4.8 in both Rhion 7 & 8.
The native library is a dependency of a dependency so I do not have control of the load point.

I found a workaround - one solution is to use a NativeLibrary.SetDllImportResolver see documentation here.
This allows you to prompt the .net runtime with the path of the dll’s on disk.
The tricky part is that these resolvers have to be added to each assembly (dll) in your project which needs to resolve the dll. In our case I had to add a resolver to one of our dependencies also.
Maybe there is a more elegant or global solution to add the path.

Anyway I leave my code below in case anyone runs into this.
It is specific to loading OpenCVSharp but should be easy enough to modify

using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

namespace Dalmatian;

public static class OpenCVResolver {
	private static string _assemblyLocation = string.Empty;
	private const  string RuntimeFolder64  = @"\runtimes\win-x64\native\";
	private const  string RuntimeFolder86  = @"\runtimes\win-x86\native\";

	public static void Start() {
		// first find out where our plugin lives on disk
		var executingAssembly = Assembly.GetExecutingAssembly();
		_assemblyLocation = Path.GetDirectoryName(executingAssembly.Location);
		// then add a resolver to both our plugin dll and to OpenCVSharp.dll 
		NativeLibrary.SetDllImportResolver(executingAssembly, Resolver);
		var opencv = Assembly.GetAssembly(typeof(OpenCvSharp.Cv2));
		if (opencv != null) {
			NativeLibrary.SetDllImportResolver(opencv, Resolver);
		}
	}

	private static IntPtr Resolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) {
		if (libraryName.Contains("opencv", StringComparison.InvariantCultureIgnoreCase)) {
			var proposedPath = _assemblyLocation
			                 + (Environment.Is64BitProcess ? RuntimeFolder64 : RuntimeFolder86)
			                 + libraryName + ".dll";
			if (File.Exists(proposedPath)) {
				return NativeLibrary.Load(proposedPath, assembly, searchPath);
			}

		}
		return IntPtr.Zero;
	}
}
1 Like