我正在绞尽脑汁试图想出一个解决DLL加载问题的优雅解决方案。我有一个静态链接到其他加载DLL的lib文件的应用程序。我没有直接加载DLL。我想在可执行文件所在的文件夹之外的另一个文件夹中安装一些DLL。像%working_folder%\ dlls这样的东西 - 我宁愿在我的%working_folder%中没有几十个(是...几十个)DLL 。
我正在尝试开发一些主要应用程序的一部分,它将调整@ startup的搜索路径。我遇到的问题是这个新的自定义DLL路径不在系统搜索路径中。当我启动应用程序时它崩溃(STATUS_DLL_NOT_FOUND)因为必要的DLL不在适当的位置。我想做的是检查@ startup是否这个新的自定义DLL文件夹在进程环境变量搜索路径中,如果没有添加它。问题是,应用程序尝试在应用程序执行一行代码之前加载所有这些DLL。
我该如何解决这个问题?我考虑过编写一个首先启动的帮助应用程序,适当调整环境变量,然后通过CreateProcess启动主应用程序。这将有效我确信它,但它使开发人员的事情变得困难。当他们调试主应用程序时,他们不会首先启动帮助应用程序 - 而不是他们甚至可以这样做。
我尝试过注册表应用程序路径功能但没有成功。像以前一样鸡和鸡蛋问题。
我可以在这做什么?
答案 0 :(得分:3)
我发现马修的答案对我有用。
在visual studio 2012中转到您的项目属性并进入 配置属性 - >链接器 - >输入 - >延迟加载的Dll 添加您想要在需要之前不加载的每个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.
答案 1 :(得分: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后更改工作目录。
答案 2 :(得分:2)
我的建议是使用DLL的延迟加载链接并尽早调用SetDllDirectory(),以便在调用方法/函数时找到它们。