确定DLL的加载路径
我希望我的应用程序具有以下结构。
Exe
|
|----- DLL\DLL.dll, DLL\common.dll
|
|----- DLL2\DLL2.dll, DLL2\common.dll
我的 EXE 将通过 DLL.dll 加载 DLL
LoadLibraryEx(_T("DLL\\DLL.dll"), 0, 0);
LoadLibraryEx(_T("DLL2\\DLL2.dll"), 0, 0);
,而 DLL2.dll 项目将通过 lib 文件链接到 common.dll。不过,common.dll
将有 2 个不同版本。
但是,在执行过程中,Exe
希望我将 common.dll
放置在与 Exe
相同的目录中,但与 DLL
放置在不同的目录中代码>和<代码>DLL2。有什么办法可以通过上述目录结构来解决这个问题。然而,仍然使用 lib 与 common
链接到 DLL/DLL2
。
I wish to have my application in the following structure.
Exe
|
|----- DLL\DLL.dll, DLL\common.dll
|
|----- DLL2\DLL2.dll, DLL2\common.dll
My EXE will load the DLLs through
LoadLibraryEx(_T("DLL\\DLL.dll"), 0, 0);
LoadLibraryEx(_T("DLL2\\DLL2.dll"), 0, 0);
DLL.dll
and DLL2.dll
project will link against common.dll
through lib file. There will be 2 different versions of common.dll
though.
However, during execution, Exe
expected me to place common.dll
same directory as Exe
, but not same directory as DLL
and DLL2
. Is there any way I can resolve this, by able to have the above directory structure. Yet, still use lib to link against DLL/DLL2
with common
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您想要将两个具有相同名称 (common.dll) 的不同 DLL 加载到同一进程中。
这对我来说似乎是个坏主意。真的有必要吗?其中之一可以重命名吗?
确保您加载的 DLL 可以找到不在搜索路径中的其他 DLL。
(如果您没有动态加载 DLL.dll 和 DLL2.dll,那么我不确定会是什么。幸运的是,我发现您是动态加载的。:))
如果您动态加载 DLL.dll 和 DLL2.dll(即在运行时使用 LoadLibrary,而不是在构建时链接到它们的 .lib 文件),那么您可以调用 SetDllDirectory 将 DLL 或 DLL2 目录显式添加到搜索路径。您希望路径中一次只包含一个目录,以确保加载正确的 common.dll。
请注意,除非它破坏了编写得不好的组件,否则最好在程序开始时调用 SetDllDirectory("") 来删除当前工作目录(而不是程序目录,不用担心)从 DLL 搜索路径中。这可以缓解您的代码可能被欺骗加载 DLL 的安全问题。但还要注意,如果您通过调用 SetDllDirectory(NULL) 重置搜索路径,则之后需要再次调用 SetDllDirectory("")。
所以你会有这样的代码:(
未经测试,所以对任何错误或丢失参数表示歉意。不过应该给你这个想法。)
(你应该在运行时计算 C:\MyExePath。显然,硬编码它会很糟糕.)
(我假设 DLL.dll 和 DLL2.dll 隐式加载它们的 common.dll。如果它们通过 LoadLibrary 调用加载 common.dll,那么问题就更简单了:只需让它们计算自己的路径,然后传递 LoadLibrary common.dll 的完整路径。)
请注意:SetDllDirectory 会影响您的整个进程。如果您的进程有多个线程,您应该确保 SetDllDirectory 调用以及可能触发 LoadLibrary 调用的任何其他调用彼此隔离。例如,如果可能的话,在生成任何其他线程之前在启动时加载库。
You want to load two different DLLs with the same name (common.dll) into the same process.
That seems like a bad idea to me. Is it really necessary? Could one of them be renamed?
Ensuring the DLLs you load can find other DLLs which aren't in the search path.
(If you were not dynamically loading DLL.dll and DLL2.dll then I'm not sure what the would be. Luckily, I see you are. :))
If you are dynamically loading DLL.dll and DLL2.dll (that is, using LoadLibrary at runtime instead of linking to their .lib files at build time), then you can call SetDllDirectory beforehand to explicitly add the DLL or DLL2 directories to the search path. You would want to only have one directory in the path at once to ensure the right common.dll was loaded.
Note that it is good practice, unless it breaks a poorly-written component, to call SetDllDirectory("") at the start of your program to remove the current-working-directory (not the program's directory, don't worry) from the DLL search path. This mitigates security issues where your code can be tricked into loading DLLs. But also note that if you reset the search path by calling SetDllDirectory(NULL) then you need to call SetDllDirectory("") again afterwards.
So you'd have code like this:
(Untested so apologies for any mistakes or missing arguments. Should give you the idea, though.)
(You should calculate the C:\MyExePath at runtime. Hard-coding it would be bad, obviously.)
(I am assuming that DLL.dll and DLL2.dll load their common.dll implicitly. If they are loading common.dll via a LoadLibrary call then the problem is even easier: Just make them calculate their own paths and then pass LoadLibrary the full path to common.dll.)
Beware: SetDllDirectory affects your entire process. If your process has multiple threads you should ensure the SetDllDirectory calls are isolated from each other as well as anything else that may trigger a LoadLibrary call. e.g. Load the libraries at startup before you spawn any other thread, if possible.
这是行不通的。您无法将“DLL2\DLL2.dll”链接到“DLL2\common.dll”。 DLL2.dll 将链接到“DLL\common.dll”。当加载“DLL2.dll”时,内存中将会有一个“common.dll”,因此 DLL2.dll 的导入将根据该 DLL 进行解析。
请注意,
PATH
或SetDllDirectory
等建议不起作用。它们会影响LoadLibrary
查找“common.dll”的方式,但对于 DLL\DLL.dll,LoadLibrary("common.dll")
仅调用一次。It won't work. You can't link "DLL2\DLL2.dll" to "DLL2\common.dll". DLL2.dll will be linked against "DLL\common.dll". There will be a "common.dll" in memory when "DLL2.dll" is loaded, so the imports of DLL2.dll will be resolved against that DLL.
Note that suggestions such as
PATH
orSetDllDirectory
do not work. They affect howLoadLibrary
finds "common.dll", butLoadLibrary("common.dll")
is called only once, for DLL\DLL.dll.好吧,这真的很有趣。
这里的基本原则是,要从其他路径加载 DLL,您必须指定完整路径(使用 LoadLibrary 时)或扩展 PATH 环境变量以包含包含 DLL 的其他文件夹。有关如何执行此操作的详细信息,请参阅 setenv。
一个简单的解决方案是提供 LoadLibrary 的相对路径。但似乎您正在链接 DLL,因此您无法应用此解决方案。
问题是无论您的项目布局是什么,运行时链接器都将使用当前工作目录和 PATH 变量。由于您似乎正在链接该库,因此您不可能在加载第一个 DLL 之后和第二个 DLL 之前“修复”PATH 变量。剩下的解决方案是将公共 DLL 重命名为 common-1.dll 和 common-2.dll 之类的名称。这还有一个好处,您实际上可以将它们全部放入同一目录中。
(如果您在任何情况下都使用 LoadLibrary,那么只需修复 PATH 变量...)
Ok this will really be fun.
The basic thing here is, to load the DLLs from other paths, you either must specify the full path (when using LoadLibrary) or expand the PATH environment variable to include the other folders that contain your DLLs. See setenv for details on how to do that.
A simple solution is to provide the relative path to LoadLibrary. But is seems you are linking the DLLs and thus you can't apply this solution.
The problem is no matter what your project layout is the runtime linker will use the current working directory and the PATH variable. Since you seem to be linking the library there is no chance you can "fix" the PATH variable just after loading the first DLL and before the second DLL. The remaining solution is to rename the common DLL to something like common-1.dll and common-2.dll. This also has the benefit that you can actually put them all into the same directory.
(If you are using LoadLibrary in any case, then just fix the PATH var...)