Добавить пользовательский путь поиска DLL при запуске приложения
Я ломаю голову, пытаясь найти элегантное решение проблемы загрузки DLL. У меня есть приложение, которое статически ссылается на другие файлы lib, которые загружают библиотеки DLL. Я не загружаю DLL напрямую. Я хотел бы иметь несколько DLL-файлов в другой папке, отличной от папки, в которой находится исполняемый файл. Что-то вроде%working_folder%\dlls - я бы предпочел, чтобы в моем% working_folder% не было десятков (да... десятков) DLL.,
Я пытаюсь разработать что-то, что является частью основного приложения, которое будет корректировать путь поиска при запуске. Проблема, с которой я сталкиваюсь, заключается в том, что этот новый пользовательский путь к DLL отсутствует в системном пути поиска. Когда я запускаю приложение, оно падает (STATUS_DLL_NOT_FOUND), потому что необходимые DLL не находятся в соответствующих местах. Что я хотел бы сделать, это проверить @ startup, если эта новая пользовательская папка DLL находится в пути поиска переменной среды процесса, и если нет, добавить ее. Проблема в том, что приложение пытается загрузить все эти библиотеки DLL, прежде чем приложение выполнит одну строку кода.
Как это исправить? Я подумал о написании справочного приложения, которое запускается первым, корректирует переменные среды соответствующим образом и запускает главное приложение через CreateProcess. Это будет работать, я в этом уверен, но это усложняет работу разработчиков. Когда они отлаживают основное приложение, они не собираются сначала запускать вспомогательное приложение - не то чтобы они даже могли это сделать.
Я попробовал функцию пути к реестру безуспешно. Та же проблема с курицей и яйцом, что и раньше.
Что я могу сделать здесь?
3 ответа
Я нашел ответ Мэтью работал для меня.
В 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.
[Изменить - после перечитывания вопроса я вижу, что проблема в том, что библиотеки DLL загружаются раньше main
начинается]
Я предполагаю, что эти библиотеки написаны на C++ и загружают библиотеки DLL из конструктора некоторых объектов в глобальной области видимости. Это проблематично. Позвольте мне процитировать Йосси Крейнина:
Сделайте это первым делом в main(). Если вы используете C++, вы должны сделать это прежде, чем main(), потому что люди могут использовать FP в конструкторах глобальных переменных. Это может быть достигнуто путем выяснения порядка инициализации модуля перевода для конкретного компилятора, компиляции вашей собственной библиотеки запуска C/C++, переопределения точки входа скомпилированной библиотеки запуска с использованием таких вещей, как LD_PRELOAD, перезаписи ее в статически связанной программе прямо в двоичном изображении, имея соглашение о кодировании, заставляющее вызывать FloatingPointSingleton::instance() перед использованием FP, или расстреливать людей, которые любят делать что-то перед main(). Это компромисс.
[Оригинальный ответ ниже]
Смотрите эту страницу для алгоритма поиска, используемого для загрузки DLL. Ты можешь использовать SetDllDirectory()
добавить каталог в путь поиска DLL.
Вы также должны иметь возможность добавить каталог в переменную окружения PATH, используя GetEnvironmentVariable()
а также SetEnvironmentVariable()
,
Другой вариант - изменить текущий рабочий каталог на папку, содержащую библиотеки DLL с SetCurrentDirectory()
, Просто убедитесь, что вы изменили рабочий каталог после загрузки DLL, если вы когда-либо загружаете какие-либо файлы, используя относительные имена файлов.
Я рекомендую использовать связывание с задержкой загрузки для DLL и вызывать SetDllDirectory() достаточно рано, чтобы он мог найти их при вызове методов / функций.