在同一个进程中加载​​同一个 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

在托管 DLL 中加载 C++ DLL 时出现 EEFileLoadException

无法在 python (3.4) 中加载 dll 文件

在 Windows 中的 Qt 中加载外部 dll

无法在 WPF 项目中加载 DLL