14

In .Net Core, you can PInvoke with [DllImport],

But if you want to dynamically load and map native api calls, DllImport doesn't solve the problem.

On windows we handled this with a DllImport to LoadModule. Then you could use GetProcAddress to map an address to a delegate which you could then call, effectively dynamically loading api calls.

Is there any way to do this in .Net Core out of the box so that your logic doing the loading works cross platform on Linux, Mac OSX, and Windows?

This can be built, but I'm trying to see if there's a way to do this before I chase that rabbit.

Ryan Mann
  • 5,178
  • 32
  • 42
  • Not something I've tried but I found a couple examples here, look for text on this page "getpid(2) is a standard POSIX system call" to see a Linux example: https://github.com/dotnet/docs/blob/master/docs/standard/native-interop.md – AaronLS Mar 14 '18 at 14:47
  • Sorry, realizing that example is using DllImport... – AaronLS Mar 14 '18 at 14:51
  • There are ways to use DllImport at runtime, but I'm not sure how that will translate to Core/other platforms: https://stackoverflow.com/a/2818948/84206 – AaronLS Mar 14 '18 at 14:54
  • Yeah, that last one is how you do it on windows. You can do it simillary on Linux. To build a library to do this, would require 3 Assemblies at least I think. You build one loader against windows, then one against linux, then in your main assembly say "XYZ.PInvokeLoader" you dynamically load (via reflection) either your WIndows loader, or linux loader based on the current operating system at runtime (Managed Assemblies). Then you could just call a static method like "LoadLibrary". on windows that would be LoadLibrary and on Linux it would call DLOpen. – Ryan Mann Mar 14 '18 at 14:58
  • 1
    If you don't get traction here, you might consider opening an issue in Core on github since they implemented the cross platform DllImport, and they might have a better solution to for runtime imports or consider adding it as a feature. Although they'd probably make it low priority. – AaronLS Mar 14 '18 at 15:07
  • 1
    Thanks for that, I opened an issue and got a good response. It is slated to be added to .NetCore in the future but won't be in 2.1. However someone has implemented what I was thinking about writing already as a prototype for .NetCore: https://github.com/mellinoe/nativelibraryloader This is close to the concept I was considering building. I think I'm going to tweak it a step farther so it can handle alternate linux libs for DLOpen. – Ryan Mann Mar 14 '18 at 18:44

2 Answers2

8

One potential solution is related to my answer to the SO question Load unmanaged static dll in load context:

You can use AssemblyLoadContext in System.Runtime.Loader package.

Your implementation for LoadUnmanagedDll() contains the logic to load platform dependent native libraries:

string arch = Environment.Is64BitProcess ? "-x64" : "-x86";
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
    var fullPath = Path.Combine(assemblyPath, "runtimes", "osx" + arch, "native", "libnng.dylib");
    return LoadUnmanagedDllFromPath(fullPath);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
    var fullPath = Path.Combine(assemblyPath, "runtimes", "linux" + arch, "native", "libnng.so");
    return LoadUnmanagedDllFromPath(fullPath);
}
else // RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
{
    var fullPath = Path.Combine(assemblyPath, "runtimes", "win" + arch, "native", "nng.dll");
    return LoadUnmanagedDllFromPath(fullPath);
}

The runtimes/platform/native/ is the nupkg convention but you can use any path you like.

Your pinvoke methods will be similar to:

[DllImport("nng", CallingConvention = CallingConvention.Cdecl)]
public static extern int nng_aio_alloc(out nng_aio aio, AioCallback callback, IntPtr arg);

Calling a native method like nng_aio_alloc through the shared interface will trigger then load of nng library and your LoadUnmanagedDll() function will get called.

Jake
  • 1,304
  • 9
  • 11
2

After opening an issue on the .NetCore Repo, I was informed this is slated to be added to .Net Core, but won't be in 2.1.

Currently there is a Prototype Implementation created by a user on github located here:

https://github.com/mellinoe/nativelibraryloader

Ryan Mann
  • 5,178
  • 32
  • 42