确定DLL的加载path

我希望在以下结构中有我的申请。

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 。 虽然会有2个不同版本的common.dll

但是,在执行期间, Exe期望我把common.dllExe相同的目录下,但不能和DLLDLL2 。 有什么办法可以解决这个问题,通过能够有上述的目录结构。 不过,还是使用lib与common DLL/DLL2链接。

  1. 您想要将具有相同名称(common.dll)的两个不同的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(“”)。

所以你会有这样的代码:

 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调用的东西。 例如,如果可能的话,在生成任何其他线程之前,在启动时加载库。

它不会工作。 您不能将“DLL2 \ DLL2.dll”链接到“DLL2 \ common.dll”。 DLL2.dll将链接到“DLL \ common.dll”。 当“DLL2.dll”加载时,内存中将会出现“common.dll”,所以DLL2.dll的导入将会针对该DLL进行解析。

请注意,建议如PATHSetDllDirectory不起作用。 它们影响LoadLibrary如何找到“common.dll”,但LoadLibrary("common.dll")只被调用一次,用于DLL \ DLL.dll。

好吧,这真的很有趣。

这里最基本的一点是,要从其他路径加载DLL,您必须指定完整路径(使用LoadLibrary时)或展开PATH环境变量以包含其他包含您的DLL的文件夹。 有关如何执行此操作的详细信息,请参阅setenv。

一个简单的解决方案是提供LoadLibrary的相对路径。 但似乎你链接的DLL,因此你不能应用这个解决方案。

问题是无论您的项目布局是什么,运行时链接程序都将使用当前工作目录和PATH变量。 由于您似乎正在链接库,因此您无法在加载第一个DLL之后和第二个DLL之前“修复”PATH变量。 剩下的解决方法是将common DLL重命名为common-1.dll和common-2.dll。 这也有好处,你可以把它们放到同一个目录中。

(如果你在任何情况下使用LoadLibrary,那么只需修复PATH变种…)