添加自定义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搜索路径@应用启动的主要内容,如果未能解决你的问题,请参考以下文章

如何在.NET 运行时将文件夹添加到程序集搜索路径?

在debian10启动器中添加自定义应用

将自定义类库 (dll) 添加到项目的问题

从帮助菜单中删除(或自定义)“搜索”

C# 自定义exe引用的dll路径

vs2010怎么新建一个用户自定义控件,最后能够导出用户自定义控件的dll文件