Динамическая загрузка 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, Есть два общих объяснения этому:

  1. Файл пакета не может быть найден поиском DLL. Возможно, имя было неправильным, или пакет не находится в месте, в котором выполняется поиск по алгоритму поиска DLL.
  2. Файл пакета может быть найден, но не может быть найдена одна из его зависимостей. Например, возможно rtl пакет не может быть найден.

Устраните проблему, используя Dependency Walker. Используйте его в режиме профиля, и он скажет вам, какой модуль не может быть найден.

Другие вопросы по тегам