12

我绞尽脑汁试图想出一个优雅的解决方案来解决 DLL 加载问题。我有一个静态链接到加载 DLL 的其他 lib 文件的应用程序。我没有直接加载 DLL。我想在可执行文件所在的文件夹之外的另一个文件夹中有一些 DLL。像 %working_folder%\dlls 之类的东西 - 我宁愿在我的 %working_folder% 中没有几十个(是的......几十个)DLL .

我正在尝试开发一些作为主应用程序一部分的东西,它将调整搜索路径@启动。我遇到的问题是这个新的自定义 DLL 路径不在系统搜索路径中。当我启动应用程序时,它会崩溃(STATUS_DLL_NOT_FOUND),因为必要的 DLL 不在适当的位置。我想做的是检查@startup这个新的自定义DLL文件夹是否在进程环境变量搜索路径中,如果没有添加它。问题是,应用程序会在应用程序执行一行代码之前尝试加载所有这些 DLL。

我该如何解决?我考虑过编写一个帮助应用程序,它首先启动,适当地调整环境变量并通过 CreateProcess 启动主应用程序。我敢肯定这会奏效,但它会让开发人员感到困难。当他们调试主应用程序时,他们不会首先启动辅助应用程序——他们甚至不能这样做。

我尝试了注册表应用程序路径功能,但没有成功。和以前一样的鸡和蛋问题。

我可以在这里做什么?

4

3 回答 3

3

我发现马修的回答对我有用。

在 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.
于 2014-03-28T12:01:27.593 回答
2

我的建议是对 DLL 使用延迟加载链接,并尽早调用 SetDllDirectory(),以便在调用方法/函数时找到它们。

于 2010-01-05T02:22:51.077 回答
2

[编辑 - 重新阅读问题后,我发现您遇到的问题是 DLL 在main开始之前被加载]

我猜这些库是用 C++ 编写的,并且正在从全局范围内某些对象的构造函数中加载 DLL。这是有问题的。请允许我引用Yossi Kreinin的话:

在 main() 中做第一件事。如果你使用 C++,你应该在 main() 之前做第一件事,因为人们可以在全局变量的构造函数中使用 FP。这可以通过确定编译器特定的翻译单元初始化顺序、编译您自己的 C/C++ 启动库、使用 LD_PRELOAD 之类的东西覆盖已编译启动库的入口点、在静态链接程序中覆盖它来实现在二进制图像中,有一个编码约定强制在使用 FP 之前调用 FloatingPointSingleton::instance(),或者在 main() 之前拍摄喜欢做事的人。这是一个权衡。

[下面的原始答案]

有关用于加载 DLL 的搜索算法,请参见此页面。您可以使用SetDllDirectory()将目录添加到 DLL 搜索路径。

您还应该能够使用GetEnvironmentVariable()和将目录添加到 PATH 环境变量SetEnvironmentVariable()

另一种选择是将当前工作目录更改为包含带有 .dll 的 DLL 的文件夹SetCurrentDirectory()。如果您曾经使用相对文件名加载任何文件,请确保在加载 DLL 后将工作目录改回。

于 2008-11-29T03:33:45.973 回答