确定DLL的加载路径

时间:2010-12-08 09:16:27

标签: c++ windows visual-studio dll

我希望将我的申请纳入以下结构。

Exe
 |
 |----- DLL\DLL.dll, DLL\common.dll 
 |
 |----- DLL2\DLL2.dll, DLL2\common.dll

我的EXE将通过

加载DLL
LoadLibraryEx(_T("DLL\\DLL.dll"), 0, 0);
LoadLibraryEx(_T("DLL2\\DLL2.dll"), 0, 0);

DLL.dllDLL2.dll项目将通过lib文件链接到common.dll。不过,common.dll会有2个不同版本。

但是,在执行期间,Exe期望我将common.dll目录与Exe放在同一目录中,但与DLLDLL2不同。有没有办法解决这个问题,能够拥有上述目录结构。但是,仍然使用lib将DLL/DLL2common链接起来。

3 个答案:

答案 0 :(得分:5)

  1. 您希望将两个名称相同的DLL(common.dll)加载到同一进程中。

    这对我来说似乎是一个坏主意。真的有必要吗?其中一个可以重命名吗?

  2. 确保加载的DLL可以找到不在搜索路径中的其他DLL。

    (如果你没有动态加载DLL.dll和DLL2.dll那么我不确定它会是什么。幸运的是,我看到你是。:))

    如果您正在动态加载DLL.dll和DLL2.dll(即在运行时使用LoadLibrary而不是在构建时链接到其.lib文件),那么您可以事先调用SetDllDirectory以显式添加DLL或DLL2目录到搜索路径。您可能希望一次只在路径中有一个目录,以确保加载了正确的common.dll。

    请注意,除非打破写得不好的组件,否则最好在程序开头调用SetDllDirectory(“”)来删除当前工作目录(程序的目录,不要担心)从DLL搜索路径。这可以减轻安全问题,在这些问题中,您的代码可能会被欺骗加载DLL。但另请注意,如果通过调用SetDllDirectory(NULL)重置搜索路径,则需要再次调用SetDllDirectory(“”)。

  3. 所以你有这样的代码:

    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的导入。

请注意,PATHSetDllDirectory等建议不起作用。它们会影响{​​{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 ...)

相关问题