Динамическая загрузка BPL завершается неудачно в LoadLibrary
Я хотел бы динамически загружать модули BPL в проекте Delphi 10 Seattle (обновление 1) или Delphi 10.1 Berlin (версия Enterprise). Но функция LoadPackage завершается с сообщением (как на 32, так и на 64-битной целевой платформе):
Проект LoadPackageTest.exe поднял класс исключения EPackageError с сообщением "Не удается загрузить пакет" реальный путь здесь "\TestBplPackage.bpl. Указанный модуль не может быть найден'.
Моя платформа разработки - Windows 10 Pro 64 bit.
Я уверен, что переданное имя файла является правильным (оно содержит полный путь). Что я сделал до сих пор:
Та же группа проектов работает без проблем (мне пришлось заново создавать ее), если она скомпилирована с Delphi 2007 Enterprise - на том же ПК с Win 10
Если я загружаю стандартный.DLL - он загружается правильно, и я могу вызывать функции в D2007, D10 и D10.1 (работает как для 32-, так и для 64-битных целей на D10 и D10.1).
На самом деле LoadPackage вызывает SafeLoadLibrary, который вызывает LoadLibrary (все эти процедуры находятся в System.SysUtils.
Я скомпилировал исполняемый файл тестирования с пакетами времени выполнения и без них. Есть код:
Проект DLL (TestDLL.dpr), работает во всех случаях
library TestDLL;
uses SysUtils, Classes;
{$R *.res}
function GetMyTime: TDateTime; stdcall;
begin
Result:= Now;
end;
exports GetMyTime;
end.
Проект BPL (TestBplPackage.dpr)
package TestBplPackage;
{ standard compiler directives - the project was created with New->Package}
requires
rtl,
vcl;
contains
TestBPLUnit in 'TestBPLUnit.pas';
end.
unit TestBPLUnit;
interface
function GetMyTime: TDateTime; stdcall;
implementation
uses classes, sysutils;
function GetMyTime: TDateTime;
begin
Result:= Now;
end;
exports GetMyTime;
end.
Тестирующее приложение - LoadPackageTest.dpr
Form1: TForm содержит dOpen: TOpenDialog и Button1: TButton
type
TMyDateTimeFunction = function: TDateTime; stdcall;
procedure TForm1.Button1Click(Sender: TObject);
var
ext: string;
h: HModule;
func: TMyDateTimeFunction;
begin
if dOpen.Execute then begin
ext:= ExtractFileExt(dOpen.FileName);
if SameText(ext, '.bpl') then begin
h:= LoadPackage(PChar(dOpen.FileName));
if h > 0 then begin
func:= GetProcAddress(h, 'GetMyTime');
if Assigned(func) then
ShowMessage(FormatDatetime('yyyy-mm-dd hh:nn:ss', func));
UnloadPackage(h);
end;
end else if SameText(ext, '.dll') then begin
h:= LoadLibrary(PChar(dOpen.FileName));
if h > 0 then begin
func:= GetProcAddress(h, 'GetMyTime');
if Assigned(func) then
ShowMessage(FormatDatetime('yyyy-mm-dd hh:nn:ss', func));
FreeLibrary(h);
end;
end;
end; //dOpen.execute
end;
Кто-нибудь пробовал что-то подобное?
Избегайте удаления объекта из узла "Содержит" дерева диспетчера проектов - и Delphi 10, и 10.1 аварийно завершают работу...
РЕДАКТИРОВАТЬ 1: Он работает на некоторых условиях
Благодаря ответу Дэвида мне удалось достичь некоторого прогресса:
он работает должным образом, когда содержимое соответствующего
C:\Program Files (x86)\Embarcadero\Studio\18.0\Redist\
Подпапки Win32 или Win64 находятся либо в папке, где находятся приложение и тестовый BPL, либо в соответствующей папке System32 или SysWOW64.
Без всего вышесказанного мне не удалось бы заставить его работать, несмотря на то, что оба
C:\Program Files (x86)\Embarcadero\Studio\18.0\bin и
C:\Program Files (x86)\Embarcadero\Studio\18.0\bin64 были в переменной%PATH% Environment. Он не нашел пакет RTL.
Побочный эффект легко объяснить, если приложение использует переменную% PATH% для поиска необходимых BPL. Потому что у меня есть C:\Windows\SysWOW64;C:\WINDOWS\system32;C:\WINDOWS
в переменной% PATH%, если я компилирую для платформы Win32 с пакетами времени выполнения, я получаю следующее сообщение об ошибке:
Приложение не удалось правильно запустить (0xc000007b)
это потому, что 32-битное приложение пытается загрузить 64-битные BPL.
Я могу легко поменять местами System32 и SysWOW64, но это глобальная переменная, а не переменная пути пользователя, и для вступления изменений в силу требуется перезапуск.
Я продолжу экспериментировать, но до сих пор единственным 100% работающим решением является сохранение использованных " стандартных " BPL в папке вывода платформы.
1 ответ
Текст исключения указывает, что вызов LoadLibrary
не удалось и GetLastError
возвращенный ERROR_MOD_NOT_FOUND
, Есть два общих объяснения этому:
- Файл пакета не может быть найден поиском DLL. Возможно, имя было неправильным, или пакет не находится в месте, в котором выполняется поиск по алгоритму поиска DLL.
- Файл пакета может быть найден, но не может быть найдена одна из его зависимостей. Например, возможно
rtl
пакет не может быть найден.
Устраните проблему, используя Dependency Walker. Используйте его в режиме профиля, и он скажет вам, какой модуль не может быть найден.