добавить пользовательский путь поиска DLL при запуске приложения - PullRequest
9 голосов
/ 29 ноября 2008

Я ломаю голову, пытаясь найти элегантное решение проблемы загрузки DLL. У меня есть приложение, которое статически ссылается на другие файлы lib, которые загружают библиотеки DLL. Я не загружаю DLL напрямую. Я хотел бы иметь несколько DLL-файлов в другой папке, отличной от папки, в которой находится исполняемый файл. Что-то вроде% working_folder% \ dlls - я бы предпочел, чтобы в моем% working_folder% не было десятков (да ... десятков) DLL. ,

Я пытаюсь разработать что-то, что является частью основного приложения, которое будет корректировать путь поиска при запуске. Проблема, с которой я сталкиваюсь, заключается в том, что этот новый пользовательский путь к DLL отсутствует в системном пути поиска. Когда я запускаю приложение, оно падает (STATUS_DLL_NOT_FOUND), потому что необходимые DLL не находятся в соответствующих местах. Что я хотел бы сделать, это проверить @ startup, если эта новая пользовательская папка DLL находится в пути поиска переменной среды процесса, и если нет, добавить ее. Проблема в том, что приложение пытается загрузить все эти библиотеки DLL, прежде чем приложение выполнит одну строку кода.

Как мне это исправить? Я подумал о написании справочного приложения, которое запускается первым, корректирует переменные среды соответствующим образом и запускает главное приложение через CreateProcess. Это будет работать, я в этом уверен, но это усложняет работу разработчиков. Когда они отлаживают основное приложение, они не собираются сначала запускать вспомогательное приложение - не то чтобы они даже могли это сделать.

Я безуспешно пытался использовать функцию пути к реестру. Та же проблема с курицей и яйцом, что и раньше.

Что я могу сделать здесь?

Ответы [ 3 ]

3 голосов
/ 28 марта 2014

Я обнаружил, что ответ Мэтью работал на меня.

В visual studio 2012 зайдите в свойства вашего проекта и в Свойства конфигурации-> Linker-> Input-> Delay Loaded 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.
2 голосов
/ 05 января 2010

Я рекомендую использовать связывание с задержкой загрузки для DLL и вызывать SetDllDirectory () достаточно рано, чтобы он мог найти их при вызове методов / функций.

2 голосов
/ 29 ноября 2008

[Правка - после перечитывания вопроса я вижу, что проблема в том, что библиотеки загружаются до запуска main]

Я предполагаю, что эти библиотеки написаны на C ++ и загружают библиотеки DLL из конструктора некоторых объектов в глобальной области видимости. Это проблематично. Позвольте мне процитировать Йосси Крейнин :

Сделайте это первым делом в main (). Если вы используете C ++, вы должны сделать это прежде, чем main (), потому что люди могут использовать FP в конструкторах глобальных переменных. Это может быть достигнуто путем выяснения порядка инициализации модуля перевода для конкретного компилятора, компиляции вашей собственной библиотеки запуска C / C ++, переопределения точки входа скомпилированной библиотеки запуска с использованием таких вещей, как LD_PRELOAD, перезаписи в статически связанной программе прямо в двоичном изображении, с соглашением о кодировании, заставляющим вызывать FloatingPointSingleton :: instance () перед использованием FP, или расстрелом людей, которые любят делать вещи перед main (). Это компромисс.

[Оригинальный ответ ниже]

См. на этой странице алгоритм поиска, используемый для загрузки библиотек DLL. Вы можете использовать SetDllDirectory(), чтобы добавить каталог в путь поиска DLL.

Вы также сможете добавить каталог в переменную среды PATH, используя GetEnvironmentVariable() и SetEnvironmentVariable().

Другой вариант - изменить текущий рабочий каталог на папку, содержащую библиотеки DLL, с помощью SetCurrentDirectory(). Просто убедитесь, что вы изменили рабочий каталог после загрузки DLL, если вы когда-либо загружаете какие-либо файлы, используя относительные имена файлов.

...