添加自定义DLL搜索路径@应用启动
Posted
技术标签:
【中文标题】添加自定义DLL搜索路径@应用启动【英文标题】:add custom DLL search path @ application startup 【发布时间】:2008-11-29 03:04:48 【问题描述】:我绞尽脑汁想找到一个优雅的解决方案来解决 DLL 加载问题。我有一个静态链接到加载 DLL 的其他 lib 文件的应用程序。我没有直接加载 DLL。我想在可执行文件所在的文件夹之外的另一个文件夹中有一些 DLL。像 %working_folder%\dlls 之类的东西 - 我宁愿在我的 %working_folder% 中没有几十个(是的......几十个)DLL .
我正在尝试开发一些作为主应用程序一部分的东西,它将调整搜索路径@启动。我遇到的问题是这个新的自定义 DLL 路径不在系统搜索路径中。当我启动应用程序时,它会崩溃(STATUS_DLL_NOT_FOUND),因为必要的 DLL 不在适当的位置。我想做的是检查@startup这个新的自定义DLL文件夹是否在进程环境变量搜索路径中,如果没有添加它。问题是,应用程序会在应用程序执行一行代码之前尝试加载所有这些 DLL。
我该如何解决这个问题?我考虑过编写一个帮助应用程序,它首先启动,适当地调整环境变量并通过 CreateProcess 启动主应用程序。我敢肯定这会奏效,但它会让开发人员感到困难。当他们调试主应用程序时,他们不会先启动辅助应用程序——他们甚至不能这样做。
我尝试了注册表应用程序路径功能,但没有成功。和以前一样的鸡和蛋问题。
我可以在这里做什么?
【问题讨论】:
【参考方案1】:我发现马修的回答对我有用。
在 Visual Studio 2012 中,转到您的项目属性并在 Configuration Properties->Linker->Input->Delay Loaded Dlls 添加您希望在需要时才加载的每个 dll 文件。
虽然它不再需要在 main 之前运行,但这是我设置新搜索路径的代码
class RunBeforeMain
public:
RunBeforeMain()
const TCHAR* dllPathEnvName= name of env variable to directory containing dlls
const TCHAR* pathEnvName= TEXT("Path");
TCHAR newSearchPath[4096];
::GetEnvironmentVariable(dllPathEnvName, newSearchPath, MAX_PATH);
//append bin
_tcscat_s(newSearchPath, MAX_PATH, TEXT("bin;"));
size_t length = _tcslen(newSearchPath);
//append existing Path
::GetEnvironmentVariable(pathEnvName, newSearchPath + length, 4096-length);
::SetEnvironmentVariable(pathEnvName, newSearchPath);
;
static RunBeforeMain runBeforeMain; //constructor code will run before main.
【讨论】:
【参考方案2】:[编辑 - 重新阅读问题后,我发现您遇到的问题是 DLL 在 main
开始之前被加载]
我猜这些库是用 C++ 编写的,并且正在从全局范围内某些对象的构造函数中加载 DLL。这是有问题的。请允许我引用Yossi Kreinin:
在 main() 中做第一件事。如果你使用 C++,你应该在 main() 之前做第一件事,因为人们可以在全局变量的构造函数中使用 FP。这可以通过确定编译器特定的翻译单元初始化顺序、编译您自己的 C/C++ 启动库、使用 LD_PRELOAD 之类的东西覆盖已编译启动库的入口点、在静态链接程序中覆盖它来实现在二进制图像中,有一个编码约定强制在使用 FP 之前调用 FloatingPointSingleton::instance(),或者在 main() 之前拍摄喜欢做事的人。这是一个权衡。
[原答案如下]
有关用于加载 DLL 的搜索算法,请参阅 this page。您可以使用SetDllDirectory()
将目录添加到DLL 搜索路径。
您还应该能够使用GetEnvironmentVariable()
和SetEnvironmentVariable()
将目录添加到PATH 环境变量。
另一种选择是将当前工作目录更改为包含带有SetCurrentDirectory()
的DLL 的文件夹。如果您曾经使用相对文件名加载任何文件,请确保在加载 DLL 后将工作目录改回。
【讨论】:
Windows 在 OS X 中是否有类似 @load_path 的东西?即定义相对于当前DLL的搜索路径还是什么?谢谢。【参考方案3】:我的建议是对 DLL 使用延迟加载链接,并尽早调用 SetDllDirectory(),以便在调用方法/函数时找到它们。
【讨论】:
注意:有很多你不能在 DllMain 中做的事情,比如加载注册表值。但是调用 SetDllDirectory("./dll_dir") 可能 工作。未测试。以上是关于添加自定义DLL搜索路径@应用启动的主要内容,如果未能解决你的问题,请参考以下文章