LoadLibrary()无法加载具有清单和私有程序集的DLL

8

我正在开发一个Windows应用程序(EXE),它使用多个DLL。开发环境为VCExpress 2005 (VC 8.0),仅使用C语言。

其中一些DLL是插件/附加组件/扩展,根据EXE读取的配置文件使用LoadLibrary进行动态加载。

重要的是:该应用程序必须是可移植的(可以从USB闪存驱动器或类似设备运行,无需安装),并且插件DLL可能不在与应用程序EXE相同的文件夹中(遗留原因)。

使用MSVC6很简单:编译、链接、分发EXE和DLL。

使用MSVC8,C运行时库(MSVCRT)不再随操作系统分发,因此不能依赖其已安装。为了满足可移植性要求,我需要使用私有程序集。所有EXE和DLL都已嵌入其清单。

我的问题:通过LoadLibrary()加载的插件DLL找不到在EXE文件夹中的私有程序集,因此除非在winSxS中安装Microsoft.VC80.CRT程序集,否则尝试加载它们将失败。

问题所在:如果从插件DLL中删除清单,则一切正常。

我的问题

在问题情况下,Windows似乎没有遵循程序集搜索顺序动态链接库搜索顺序。具体来说,它正在从加载DLL的路径寻找私有程序集,而不是从加载应用程序(EXE)的路径寻找。
我已经尝试通过将程序集放在DLL旁边,并更改当前目录(排除与工作目录相关的情况),并获得了预期的行为来验证这一点。还有其他人可以确认使用SxS时这是正常行为吗?
没有清单,我是否正确地认为,DLL会回退到非SxS加载顺序,即在EXE文件夹中查找msvcr80.dll(而不是程序集清单Microsoft.VC80.CRT.manifest)?
如果我对(1)和(2)正确,那么仅排除清单会损失什么?换句话说,为什么我不应该通过仅排除清单来解决我的问题?
2个回答

10

要理解这个问题,需要先了解激活上下文是什么。

具有清单的exe或dll具有激活上下文——激活上下文是在解析清单时发现的窗口类、依赖程序集、dll和注册自由com引用的列表。

没有清单的exe或dll使用进程默认的激活上下文——通常是exe的激活上下文,如果exe有激活上下文的话。

在您的情况下,dll有自己的激活上下文——因为它有一个清单。并且始终搜索包含清单文件(或文件夹)的路径以查找程序集。

这就是为什么Windows首先在dll文件夹中搜索私有程序集。然后,当失败时,Windows搜索dll的标准加载库搜索路径:其从exe的根文件夹开始。但现在正在搜索dll,而不是程序集,因此未找到包含dll的程序集文件夹。

  1. 不会。没有清单,dll将返回使用默认激活上下文:exe的清单。这篇博客文章对此进行了一些解释。

  2. 排除清单。您失去的是让dll指定其自己的依赖程序集的能力。因此,您需要将dll所需的任何依赖程序集添加到应用程序清单中。


有一点需要补充的是,当嵌入的清单文件包含publicKeyToken引用时,加载程序似乎会忽略应用程序本地目录。 - Eric Walker
加载程序 始终 首先在WinSxS中查找,如果具有足够的信息。即使存在publicKeyToken,它也会退回到本地。 - Chris Becke

0

与CRT静态链接。只要您的应用程序中不使用.Net(纯C / C ++),就可以静态链接CRT。

在我的应用程序中引入.Net强制我从静态链接的CRT转移到动态链接的CRT。我还尝试找到一种方法,在不需要显式安装它们的情况下本地引用CRT DLL,但我没有找到。因此,如果可能,请静态链接CRT。


谢谢 - 我看到https://dev59.com/XXVC5IYBdhLWcg3wnCf6和https://dev59.com/m3RA5IYBdhLWcg3w6SNH也讨论了静态链接与动态链接的相对优点。我有些犹豫使用静态链接,因为我不确定API是否允许/期望资源分配和回收发生在不同的模块中,这将导致应用程序崩溃。此外,静态链接会导致二进制文件臃肿。 - Twylite

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接