Есть некая базовая dll, в которой некоторые функции объявлены как EXTERNAL из других dll. Приложение базовую dll загружает в run-time через LoadLibrary.
Потребовалось переместить базовую dll со всеми сопутствующими из каталога с приложением в другое место. Приложение знает путь, по которому расположена базовая dll, однако загрузка не проходит: не находятся сопутствующие dll с реализациями external-функций. Предположительно, они ищутся не в каталоге с базовой dll, а в каталоге с приложением.
Вопрос-максимум: Можно ли как-то указать, чтобы по директиве EXTERNAL dll искались в каталоге с базовой dll, а не в каталоге с приложением? Вариант — указать путь в переменной среды PATH не подходит.
Вопрос-минимум: Если никак, и надо отказываться от EXTERNAL в пользу загрузки через LoadLibrary (некая инициализация базовой dll), то как узнать путь, где эта базовая dll находится? Вроде как, нужно использовать GetModuleFileName, но торможу и не соображу, как из dll узнать хендл этой dll для передачи в функцию.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
21-10-2020 07:25 | Сообщение от автора вопроса
Изменять текущий1 каталог стремно: там куча всякого разного, а не одна единственная dll. А вот SetDllDirectory — вариант интересный, при случае буду иметь в виду.
В проекте же заменили статическую загрузку dll на динамическую с конкретизацией пути к файлу. Вроде как, работает.
Используя ChDir(), нужно помнить, что текущая директория может быть совсем не та, которую ожидает программист.
Соответственно и результат может быть неожиданным.
Например, в ярлыке программы может быть указана директория запуска, отличная от месте, где лежит исполняемый файл.
Или программу запустили иным способом, например, из командной строки, но не её из текущей директории.
Ещё некоторые стандартные диалоги могут коварным образом менять текущую директорию - например, диалог выбора файла.
Нельзя рассчитывать, что текущая директория будет всегда та, которая была при загрузке, и что она совпадает с директорией exe-шника.
Поигрался с библиотеками. Итак, вот результаты. Вкратце: если дочерняя библиотека и все её подчинённые библиотеки лежат в одной папке, то нужно ПЕРЕД LoadLibrary установить ChDir (или другим способом) эту директорию как текущую, а ПОСЛЕ LoadLibrary - вернуть всё на место. Тогда LoadLibrary подцепит статически слинкованные библиотеки корректно.
Первая библиотека (DLL улетит в папку SubFolder, которая лежит в каталоге исполняемого файла).
library Child1;
Function ChildProc1(Arg1,Arg2:integer):integer;stdcall;
begin
Result:=Arg1+Arg2;
end;
exports ChildProc1;
begin
end.
Вторая библиотека идентична (просто для примера и также улетает в SubFolder):
library Child2;
function ChildProc2(Arg1,Arg2:integer):integer;stdcall;
begin
Result:=Arg1*Arg2;
end;
exports ChildProc2;
begin
end.
Мастер-библиотека (тоже в SubFolder, статическая линковка с дочками):
library MainLib;
uses
Windows, SysUtils;
Function ChildProc1(Arg1,Arg2:integer):integer;stdcall;external 'Child1.dll';
function ChildProc2(Arg1,Arg2:integer):integer;stdcall;external 'Child2.dll';
procedure ShowResults(Arg1,Arg2:integer);stdcall;
var
S:string;
begin
S:=Format('Результаты: запрос %d, %d первый %d, второй %d',[Arg1,Arg2,ChildProc1(Arg1,Arg2),ChildProc2(Arg1,Arg2)]);
MessageBox(0,PChar(S),'Информация',MB_ICONINFORMATION);
end;
exports ShowResults;
begin
end.
Ну и код вызова:
Type
TShowResult=procedure(Arg1,Arg2:integer);stdcall;
procedure TForm1.Button1Click(Sender: TObject);
var
HLib:THandle;
Proc:TShowResult;
begin
ChDir('SubFolder');
HLib:=LoadLibrary('MainLib.dll');
if HLib=0 then
RaiseLastOSError;
try
Proc:=GetProcAddress(HLib,'ShowResults');
if @Proc=nil then
RaiseLastOSError;
Proc(1,32);
finally
FreeLibrary(HLib);
ChDir('..');
end;
end;
Если положить в System32 (или любой другой каталог из PATH), то, скорее всего, загрузится. Но меня не устраивает, так как заказчик сам выбирает каталог, куда положить библиотеки.
Текущий каталог в случае с DLL, как я понимаю, это каталог вызывающего приложения, а не каталог с базовой DLL. Опытным путем вычилено.
28-09-2020 11:07 | Комментарий к предыдущим ответам
А допустимо ли положить базовую и сопутствующие dll в какую-нибудь System32?
Размышления вслух: вроде как после каталога приложения проверяется текущий каталог. Может в приложении изменить его?
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.