我有一个程序可以将插件存储在多个目录中,如下所示:
root/
core/bin/
app.exe
core.dll
plugin.dll
support.dll
a/bin/
a.dll
a_support.dll
在此示例中,a.dll
导入core.dll
,support.dll
和a_support.dll
(它们在导入表中按此顺序排列)。 a_support.dll
导入support.dll
。我可以更改除支持模块以外的所有模块,这些模块是第三方库的重写者。
我的代码调用LoadLibraryEx(name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)
来加载每个插件。对于core.dll
和plugin.dll
,这很好用。
当我尝试加载a.dll
时,未能找到a_support.dll
。没有关于core.dll
或support.dll
的错误,可能是因为它们已经在内存中。
我怀疑在加载a_support.dll
时无法找到support.dll
,但这似乎不正常,因为a.dll
似乎在support.dll
之前导入a_support.dll
。
是否可以使用模块的布局?系统是否能够使用已经加载的支持DLL,还是会搜索它们并失败?是否有办法通过清单来处理这个问题?有没有办法使这项工作,或者我必须将所有模块重新定位到一个目录?
编辑:在Adrian McCarthy的建议下,我使用Process Monitor跟踪运行加载序列,似乎当我调用LoadLibrary("root/a/bin/a.dll", ...)
时,它首先搜索根目录,然后是系统目录,然后通过路径。出于某种原因,它从不搜索a/bin/
,这非常应该。
我仔细检查了路径,并注意到我调用加载plugin.dll
使用错误路径(root,而不是root / core / bin)。无论哪种方式,core.dll
都正确加载。修好之后,我再次尝试了,这次a.dll
找到a_support.dll
并且似乎加载了。但是,这绝对没有意义,除非加载器成功地使用support.dll
来自某个地方。即使尝试再次加载support.dll
,procmon日志也不会显示它,所以我不确定此时是否确实存在问题(除了加载器的行为没有意义)。
答案 0 :(得分:1)
当然,一种解决方案是将所有DLL放在同一目录中,与.exe相同的目录。如果你能做到这一点,那肯定是最简单的方法。
如果没有,那么你的手上会有更多的工作。我猜你期望加载器将搜索DLL所在的目录。可悲的是,它没有。相反,加载器将首先查看可执行文件的目录,然后查看DLL search order的其余部分。这就是a_support.dll
无法加载的原因,因为它与可执行文件不在同一目录中。
模块已经在内存中的事实不是重点。加载器去寻找文件。当它找到它想要的文件时,然后检查它是否已经加载。如果是这样,那么它只是将引用计数颠倒到该模块。否则它会将其加载到流程中。
您可以切换到使用LoadLibrary
进行所有DLL加载,并始终明确路径。这可能不方便。
您可以使用并排的程序集,但这听起来与插件架构不兼容。
所以我认为剩下的主要选项是SetDllDirectory
。在加载插件之前调用它。您只需要将a/bin
添加到搜索路径,因为其余模块位于可执行目录中,因此可以毫无问题地找到它们。通过再次调用SetDllDirectory
将此设置恢复为默认值,并在插件加载后传递NULL
并解决所有导入。
如果您有多个子目录,请使用AddDllDirectory
。
答案 1 :(得分:1)
我建议使用Process Monitor来查看实际发生的情况。您将看到它是否正在查找正确的位置,a_support.dll是否已打开但无法加载,因为缺少其他内容等。
答案 2 :(得分:1)
这是一个相当令人困惑的应用程序。
然后有些问题:
答案 3 :(得分:0)
我不知道你是在提供示例代码还是实际代码。你写道:
LoadLibrary("root/a/bin/a.dll", ...)
如果那是真正的代码,那么这里有两个问题。
首先,LoadLibrary
没有达到您对相对路径的期望。来自MSDN:
从相对路径加载模块而不搜索任何其他模块 path,使用GetFullPathName获取非相关路径并调用 LoadLibrary具有非相对路径。有关DLL的更多信息 搜索顺序,请参阅动态链接库搜索顺序。
基本上,你给它一个完整的路径并获取该文件,或者你让它在所有“通常”的位置搜索一个名字。如果你给它一个相对路径,它基本上忽略了那条路径,抓住了名字,并查看了通常的位置。
如果您真的想要LoadLibraryEx
,请注意当您使用LOAD_WITH_ALTERED_SEARCH_PATH
时,如果提交了相对路径,则会获得“未定义的行为”。再次引用MSDN:
如果使用此值并且lpFileName指定相对路径,则行为未定义。
其次,你有正斜杠而不是反斜杠。 LoadLibrary
和LoadLibraryEx
都不喜欢这些。