在加载上下文中加载非托管静态 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的主要内容,如果未能解决你的问题,请参考以下文章
C# Windows 窗体无法在 Windows10 上加载非托管 C++ DLL