在加载上下文中加载非托管静态 dll

Posted

技术标签:

【中文标题】在加载上下文中加载非托管静态 dll【英文标题】:Load unmanaged static dll in load context 【发布时间】:2017-03-27 14:36:49 【问题描述】:

我有本地非托管 dll,它是静态的,如果我想并行运行它,每次我需要库来做一些工作时都必须加载它。在 .NET 中,我会使用 AppDomain 并在需要时加载此 dll,但在 NET Core 中,AppDomains 已经消失(现在)。我查看了 AssemblyLoadContext,但没有与 LoadUnmanagedDll 相关的适当文档。在netstandard1.6中可以做到吗?

编辑 目前使用 PInvoke 调用代码并且运行良好。问题是因为这个 unmanged dll 的性质,当我尝试并行调用它时会抛出 AccessViolationException,因为两个或多个任务想要访问相同的内存。

如果我可以在某些情况下每次都加载 dll,然后调用 PInvoke,那么这个问题就会消失。

【问题讨论】:

AppDomains 只是窗口。由于 .net 核心在基于 Windows 和 unix 的系统上运行,因此您必须使用其他方式来加载非托管库(例如 PInvoke) 您可以使用 PInvoke 加载非托管库。它适用于单声道,很可能适用于网络核心。例如,您可以查看我的旧问题:***.com/questions/42977306/… @IvanKishchenko,请查看已编辑的问题。 修复原生库以允许多线程和/或多线程访问可能会更容易。 @omajid 库非常复杂,我无法查看源代码。还是谢谢。 【参考方案1】:

一种方法:

    System.Runtime.Loader.AssemblyLoadContext 派生类 覆盖 Load(AssemblyName assemblyName) 调用 LoadFromAssemblyPath() 或返回 null 以回退到默认上下文 覆盖 IntPtr LoadUnmanagedDll(string unmanagedDllName) 调用 LoadUnmanagedDllFromPath() 以加载您的本机 dll 间接访问您的 pinvoke 方法并通过一些已知的interface 加载本机/非托管库

第 4 步是你需要根据现有代码的结构进行调整的部分。就我而言,我创建了 3 个程序集:

    调用代码 Pinvoke 代码 前两个共享的接口

在调用代码中:

var assem = assemblyLoadContext.LoadFromAssemblyName(new 
System.Reflection.AssemblyName(pinvokeAssemblyName));
var type = assem.GetType(nameOfTypeThatCallsPinvoke);
return (ISharedInterface)Activator.CreateInstance(type);

nameOfTypeThatCallsPinvoke 的实例尝试使用pinvoke 方法时,您的LoadUnmanagedDll() 在加载上下文上的覆盖将被调用。

需要共享接口,以便在编译时知道类型。如果调用代码直接引用 pinvoke 库,则其类型将不同于通过加载上下文获得的类型。

参考资料:

AssemblyLoadContext design doc Post about using AssemblyLoadContext to load plugins (code on github) Post about using AssemblyLoadContext with a native library (code on github)(免责声明:我的)

【讨论】:

以上是关于在加载上下文中加载非托管静态 dll的主要内容,如果未能解决你的问题,请参考以下文章

获取非托管 DLL 路径以独立于版本加载 Python

这个 DLL 是托管的还是非托管的?

C# Windows 窗体无法在 Windows10 上加载非托管 C++ DLL

非静态变量 this 不能从 main 方法中的静态上下文中引用

如何创建/管理多个托管对象上下文?

C# 加载非托管 DLL:IIS 上的控制台应用程序和 webapp 之间的巨大性能差异