我正在我的 Dotnet Core 3.1 应用程序中加载一个 c++ 程序集。
如果我使用 DllImport,我可以按预期加载和使用程序集。
[DllImport(
"lib/mylibrary.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "MyEndpoint"
)]
但是,我想为平台,Windows或Linux选择合适的库。我尝试使用System.Reflection.Assembly.LoadFrom
动态加载 DLL,但这给出了错误Bad IL Format
.
我尝试了几种不同的方法,但都给出了相同的错误
读取字节数
var bytes = File.ReadAllBytes("lib/myLibrary.dll");
var assembly = System.Reflection.Assembly.Load(bytes); //bad IL format
加载自
var assembly = System.Reflection.Assembly.LoadFrom("lib/myLibrary.dll"); //bad IL format
从程序集路径加载
var assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath("lib/myLibrary.dll"); //bad IL format
//来自嵌入式资源
var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("my-library.manifestname.dll");
var assembly System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(stream); //bad IL format
我在这里做错了什么?
编辑:
溶液:
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"
)]
}
Assembly.LoadFrom
和您使用的所有其他重载处理托管程序集而不是本机库。
DllImport
只是隐藏大量机器的一种聪明方法,实际上你的原生库必须加载,大概是通过LoadLibrary
,然后运行时需要将类中声明的方法信息绑定到原生库中的导出函数,最后运行时需要在方法和函数之间进行运行时关联, 包括编组。
如果您想模拟运行时在后台所做的事情,您可以阅读此文档,它可以让您了解整个过程。请注意,这是指净标准。
请记住,DllImport
是跨平台的,而您自己的实现必须因位数(例如x64,x86,arm...(和支持的平台(例如Linux,Windows,macos...(而被拒绝,并且每个都有自己的怪癖。为此,请参阅如何在运行时指定 [DllImport] 路径?。