简体   繁体   中英

Dynamically loading BPL fails in LoadLibrary

I would like to load BPL modules dynamically in Delphi 10 Seattle (Update 1) or Delphi 10.1 Berlin project (Enterprise version). But LoadPackage function fails with message (on both 32 and 64 bit target platforms):



My development platform is Windows 10 Pro 64 bit.

I am sure that the filename passed is correct (it contains the full path). What I have done up to now:

  • The same project group works without problems (I had to re-create it from scratch) if compiled with Delphi 2007 Enterprise - on the same Win 10 PC

  • If I load standard .DLL - it is loaded properly and I can call functions in D2007, D10 and D10.1 (works for both 32 and 64 bit targets on D10 and D10.1).

Actually LoadPackage calls SafeLoadLibrary, which calls LoadLibrary (all these procedures are in System.SysUtils.

I compiled the testing executable with and without Run Time packages There is the code:

DLL project (TestDLL.dpr), works in all cases

library TestDLL;
uses SysUtils, Classes;
{$R *.res}
function GetMyTime: TDateTime; stdcall; 
begin 
  Result:= Now; 
end;
exports GetMyTime;
end.

BPL Project (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.

Testing application - LoadPackageTest.dpr

Form1: TForm contains dOpen: TOpenDialog and a 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;

Has anybody tried something similar?

Avoid deleting unit from "Contains" node of the Project manager tree - both Delphi 10 and 10.1 crash...


EDIT 1: It works on some conditions

Thanks to the David's answer, I managed to achieve some progress:
it works properly when the contents of the relevant
C:\\Program Files (x86)\\Embarcadero\\Studio\\18.0\\Redist\\
Win32 or Win64 subfolders is either in the folder where the application and the test BPL are or in relevant System32 or SysWOW64 folder.

Without the above, I could not manage to make it working despite the fact that both
C:\\Program Files (x86)\\Embarcadero\\Studio\\18.0\\bin and
C:\\Program Files (x86)\\Embarcadero\\Studio\\18.0\\bin64 were in the %PATH% Environment variable. It was not finding the package. 软件包。


There is an easy to be explained side effect if an application relies on the %PATH% variable to find the necessary BPLs. Because I have C:\\Windows\\SysWOW64;C:\\WINDOWS\\system32;C:\\WINDOWS
in the %PATH% variable, if I compile for Win32 platform with run time packages, I get the following error message:

which is because a 32 bit application attempts to load 64 bit BPLs.

I can easily swap the places of System32 and SysWOW64, but this is the global, not the user path variable and requires restart for the changes to take effect.
I will continue to experiment, but up to now the only 100% working solution is to keep the used " " BPLs into the platform output folder. ” BPL保留在平台输出文件夹中。

The exception text indicates that the call to LoadLibrary failed and GetLastError returned ERROR_MOD_NOT_FOUND . There are two common explanations for this:

  1. The package file cannot be found by the DLL search. Perhaps the name was wrong, or the package is not in a location searched by the DLL search algorithm.
  2. The package file can be found, but one of its dependencies cannot be found. For instance, perhaps the rtl package cannot be found.

Debug the issue using Dependency Walker. Use it in profile mode and it will tell you which module cannot be found.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM