在同一个进程中加载同一个 DLL 的 2 个版本
Posted
技术标签:
【中文标题】在同一个进程中加载同一个 DLL 的 2 个版本【英文标题】:Load 2 versions of the same DLL in the same process 【发布时间】:2011-06-28 10:46:58 【问题描述】:我想完全按照here 的描述去做,但接受的解决方案对我不起作用。我想原因解释here:
如果加载了具有依赖关系的 DLL 通过指定完整路径,系统 搜索 DLL 的依赖 DLL 好像他们只装载了他们的 模块名称。
如果一个具有相同模块名称的 DLL 是 已经加载到内存中,系统 仅检查重定向和 在解决之前表现出来 加载的DLL,不管是哪个目录 它在。系统不搜索 对于 DLL。
我希望我的应用程序具有以下结构。
c:\Exe
|
|----- c:\DLL\DLL.dll, c:\DLL\common.dll
|
|----- c:\DLL2\DLL2.dll, c:\DLL2\common.dll
我的 EXE 将通过以下方式加载 DLL
LoadLibrary("c:\\DLL\\DLL.dll");
LoadLibraryEx("c:\\DLL2\\DLL2.dll");
common 在这两种情况下都被隐式加载。
我尝试了 SetDllDirectory 选项,但始终只加载了一个 common.dll。
我在 common.dll 中添加了版本信息。 c:\DLL\common.dll 的版本为 2.0.1.0,而 c:\DLL2\DLL2.dll 的版本为 4.0.1.0
我在以下清单中嵌入了相应的版本信息,但没有帮助。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="common" version="4.0.1.0" processorArchitecture="x86"></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
这个问题有解决办法吗?
【问题讨论】:
【参考方案1】:您在哪里嵌入了清单? EXE 还是 DLL?
您有两种基本方法可以做到这一点,都涉及通过为其创建清单将“common”转换为私有 SxS 程序集。
然后:
如果 DLL 和 DLL2 包含列出依赖程序集的清单,则需要向它们的清单添加一个dependentAssembly,指定“acme.common”(例如)作为依赖程序集。由于总是在加载模块文件夹中搜索依赖程序集,默认情况下,每个 DLL 将加载其自己的 common 本地副本。
如果您只是依靠应用程序默认激活上下文来完成大部分繁重的工作,那么您可以尝试使用 ActivationContext API。 调用CreateActCtx 两次,指定两个不同的文件夹作为结果上下文的基本文件夹。
在伪代码中:
HACTCTX h1 = CreateActCtx( ... for DLL ... );
HACTCTX h2 = CreateActCtx( ... for DLL2 ...);
ActivateActCtx(h1,...);
LoadLibrary("C:\\DLL\\DLL1.DLL");
DeactivateActCtx();
ActivateActCtx(h2,...);
LoadLibrary("C:\\DLL2\\DLL2.DLL");
DeactivateActCtx...
如果 dll 已经包含它们自己的清单,系统将使用它们。如果没有,这将允许您为私有程序集指定搜索目录,而无需修改 dll 本身。
要实施选项 1: 首先,我不建议尝试使用 dll 名称作为程序集名称。因此,在每个文件夹中创建一个如下所示的清单:
<!-- acme.common.manifest -->
<assembly manifestVersion="1.0">
<assemblyIdentity type="Win32" name="acme.common" version="1.0.0.0" processorArchitecture="x86"/>
<file name="common.dll"/>
</assembly>
您可以修复版本号以匹配每个文件夹中的 common.dll 的版本,但这并不重要。
然后,您列出的清单或类似的指令(如果您使用的是 Visual Studio)
#pragma comment(linker, "/manifestdependency:\"acme.common'"\
" processorArchitecture='*' version='1.0.0.0' type='win32'\"")
只需确保依赖的程序集版本与相应的“acme.common”程序集的版本匹配即可。
【讨论】:
谢谢。我将清单嵌入到 DLL 中。所以,看起来我做了你在 1 推荐的事情。或者我错过了什么?清单是否正确? 我对方法1添加了一些说明。 谢谢。我让它工作了。我不得不切换到 Windows7 并使用 SxsTrace 工具来查看发生了什么。设置好后就很容易了,但是如果没有这个工具,你就看不到哪里出了问题以上是关于在同一个进程中加载同一个 DLL 的 2 个版本的主要内容,如果未能解决你的问题,请参考以下文章
如果在同一个 AppDomain 中加载了多个版本,WPF 无法选择正确的 DLL
C# 在 appdomain 调用方法中加载 dll,而不会再次加载 dll