0

I am loading a c++ assembly in my Dotnet core 3.1 application.

If I use DllImport, I can load and use the assembly as expected.

[DllImport(
    "lib/mylibrary.dll",
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "MyEndpoint"
)]

However, I want to select the appropriate library for the platform, windows or linux. I tried loading the DLL dynamically using System.Reflection.Assembly.LoadFrom but this gives the error Bad IL Format.

I have tried a few different ways, but all give the same error

// read bytes

var bytes = File.ReadAllBytes("lib/myLibrary.dll");
var assembly = System.Reflection.Assembly.Load(bytes); //bad IL format

// Load From

 var assembly = System.Reflection.Assembly.LoadFrom("lib/myLibrary.dll"); //bad IL format

//Load from assembly path

var assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath("lib/myLibrary.dll"); //bad IL format

//From embedded resource

var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("my-library.manifestname.dll");
var assembly System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(stream); //bad IL format

What am I doing wrong here?

EDIT:

solution:

static class MyWrapper
{
  static MyWrapper {
    // The linked solution suggests setting the dll path using kernel32, this only works for windows. Set Environment.CurrentDirectory instead.
    if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        Environment.CurrentDirectory = "lib/windows";
    }
    else
    {
        Environment.CurrentDirectory = "lib/unix";
    }
  }
  ...
  [DllImport(
    "my_library", //IMPORTANT: drop the extension to preserve compatibility between dylib, dll, so, etc.
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "MyEntryPoint"
  )]
}
Eamonn McEvoy
  • 8,876
  • 14
  • 53
  • 83

1 Answers1

1

Assembly.LoadFrom and all the other overloads you are using deal with managed assemblies and not native libraries.

DllImport is just a clever way to hide a lot of machinery, in fact your native library must be loaded, presumably via LoadLibrary, then the runtime needs to bind the method information declared in your class to exported function in your native library, finally the runtime needs to make the runtime association between your method and the function, including the marshaling.

If you would like to emulate what the runtime does under the hood, you can read this document which gives you an idea about the whole process. Please note that this refers to net standard.

Keep in mind the DllImport is cross platform, while your own implementation must be declined for bitness (e.g. x64, x86, arm...) and supported platforms (e.g. linux, windows, macos...) and each of them has its own quirks. For this, see How can I specify a [DllImport] path at runtime?.

Yennefer
  • 5,704
  • 7
  • 31
  • 44