我希望将我的申请纳入以下结构。
Exe
|
|----- DLL\DLL.dll, DLL\common.dll
|
|----- DLL2\DLL2.dll, DLL2\common.dll
我的EXE将通过
加载DLLLoadLibraryEx(_T("DLL\\DLL.dll"), 0, 0);
LoadLibraryEx(_T("DLL2\\DLL2.dll"), 0, 0);
DLL.dll
和DLL2.dll
项目将通过lib文件链接到common.dll
。不过,common.dll
会有2个不同版本。
但是,在执行期间,Exe
期望我将common.dll
目录与Exe
放在同一目录中,但与DLL
和DLL2
不同。有没有办法解决这个问题,能够拥有上述目录结构。但是,仍然使用lib将DLL/DLL2
与common
链接起来。
答案 0 :(得分:5)
您希望将两个名称相同的DLL(common.dll)加载到同一进程中。
这对我来说似乎是一个坏主意。真的有必要吗?其中一个可以重命名吗?
确保加载的DLL可以找到不在搜索路径中的其他DLL。
(如果你没有动态加载DLL.dll和DLL2.dll那么我不确定它会是什么。幸运的是,我看到你是。:))
如果您正在动态加载DLL.dll和DLL2.dll(即在运行时使用LoadLibrary而不是在构建时链接到其.lib文件),那么您可以事先调用SetDllDirectory以显式添加DLL或DLL2目录到搜索路径。您可能希望一次只在路径中有一个目录,以确保加载了正确的common.dll。
请注意,除非打破写得不好的组件,否则最好在程序开头调用SetDllDirectory(“”)来删除当前工作目录(不程序的目录,不要担心)从DLL搜索路径。这可以减轻安全问题,在这些问题中,您的代码可能会被欺骗加载DLL。但另请注意,如果通过调用SetDllDirectory(NULL)重置搜索路径,则需要再次调用SetDllDirectory(“”)。
所以你有这样的代码:
SetDllDirectory(NULL); // Reset.
SetDllDirectory(""); // Plug "binary planting" security hole. `
SetDllDirectory("C:\MyExePath\DLL");
LoadLibrary("C:\MyExePath\DLL\DLL.dll");
SetDllDirectory(NULL); // Reset.
SetDllDirectory(""); // Plug "binary planting" security hole.
SetDllDirectory("C:\MyExePath\DLL2");
LoadLibrary("C:\MyExePath\DLL2\DLL2.dll");
SetDllDirectory(NULL); // Reset.
SetDllDirectory(""); // Plug "binary planting" security hole.
(未经测试,对于任何错误或遗漏的论点都要道歉。不过,应该给你这个想法。)
(你应该在运行时计算C:\ MyExePath。显然硬编码很糟糕。)
(我假设DLL.dll和DLL2.dll隐式加载了他们的common.dll。如果他们通过LoadLibrary调用加载common.dll,那么问题就更容易了:只需让他们计算自己的路径然后通过LoadLibrary是common.dll的完整路径。)
注意:SetDllDirectory会影响整个过程。如果您的进程有多个线程,则应确保SetDllDirectory调用彼此隔离,以及可能触发LoadLibrary调用的任何其他调用。例如如果可能,在生成任何其他线程之前,在启动时加载库。
答案 1 :(得分:3)
它无效。您无法将“DLL2 \ DLL2.dll”链接到“DLL2 \ common.dll”。 DLL2.dll将链接到“DLL \ common.dll”。加载“DLL2.dll”时,内存中会出现“common.dll”,因此将针对该DLL解析DLL2.dll的导入。
请注意,PATH
或SetDllDirectory
等建议不起作用。它们会影响{{1}}找到“common.dll”的方式,但{DLL} DLL.dll只会调用LoadLibrary
一次。
答案 2 :(得分:0)
好的,这真的很有趣。
这里的基本要点是,要从其他路径加载DLL,您必须指定完整路径(使用LoadLibrary时)或扩展PATH环境变量以包含包含DLL的其他文件夹。有关如何执行此操作的详细信息,请参阅setenv。
一个简单的解决方案是提供LoadLibrary的相对路径。但似乎您正在链接DLL,因此您无法应用此解决方案。
问题在于,无论您的项目布局是什么,运行时链接器都将使用当前工作目录和PATH变量。由于您似乎在链接库,因此您无法在加载第一个DLL之后和第二个DLL之前“修复”PATH变量。剩下的解决方案是将公共DLL重命名为common-1.dll和common-2.dll。这样做的好处是,您可以将它们全部放入同一目录中。
(如果您在任何情况下都使用LoadLibrary,那么只需修复PATH var ...)