简体   繁体   English

动态加载BPL在LoadLibrary中失败

[英]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). 我想在Delphi 10 Seattle(更新1)或Delphi 10.1 Berlin项目(企业版)中动态加载BPL模块。 But LoadPackage function fails with message (on both 32 and 64 bit target platforms): 但是LoadPackage函数失败并显示消息(在32位和64位目标平台上):


Project LoadPackageTest.exe raised exception class EPackageError with message 'Can't load package "real path here"\\TestBplPackage.bpl. Project LoadPackageTest.exe引发异常类EPackageError,并显示消息“无法在此处加载程序包的真实路径” \\ TestBplPackage.bpl。 The specified module could not be found'. 指定的模块无法找到'。


My development platform is Windows 10 Pro 64 bit. 我的开发平台是Windows 10 Pro 64位。

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 如果在同一台Win 10 PC上使用Delphi 2007 Enterprise进行编译,则相同的项目组可以正常工作(我必须从头开始重新创建它)

  • 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). 如果我加载标准.DLL-它将正确加载,并且可以在D2007,D10和D10.1中调用函数(适用于D10和D10.1上的32位和64位目标)。

Actually LoadPackage calls SafeLoadLibrary, which calls LoadLibrary (all these procedures are in System.SysUtils. 实际上,LoadPackage调用了SafeLoadLibrary,后者调用了LoadLibrary(所有这些过程都在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 DLL项目(TestDLL.dpr),在所有情况下均有效

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

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

Testing application - LoadPackageTest.dpr 测试应用程序-LoadPackageTest.dpr

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

Has anybody tried something similar? 有人尝试过类似的东西吗?

Avoid deleting unit from "Contains" node of the Project manager tree - both Delphi 10 and 10.1 crash... 避免从项目管理器树的“包含”节点中删除单元-Delphi 10和10.1都崩溃...


EDIT 1: It works on some conditions 编辑1:它在某些条件下工作

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\\ 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. Win32Win64子文件夹位于应用程序和测试BPL所在的文件夹中,或者位于相关的System32SysWOW64文件夹中。

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 \\ bin
C:\\Program Files (x86)\\Embarcadero\\Studio\\18.0\\bin64 were in the %PATH% Environment variable. C:\\ Program Files(x86)\\ Embarcadero \\ Studio \\ 18.0 \\ bin64位于%PATH%环境变量中。 It was not finding the RTL package. 它没有找到RTL软件包。


There is an easy to be explained side effect if an application relies on the %PATH% variable to find the necessary BPLs. 如果应用程序依赖于%PATH%变量来查找必要的BPL,则有一个容易解释的副作用。 Because I have C:\\Windows\\SysWOW64;C:\\WINDOWS\\system32;C:\\WINDOWS 因为我有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: 在%PATH%变量中,如果我使用运行时程序包为Win32平台编译,则会收到以下错误消息:
The application was unable to start correctly (0xc000007b) 应用程序无法正确启动(0xc000007b)
which is because a 32 bit application attempts to load 64 bit BPLs. 这是因为32位应用程序尝试加载64位BPL。

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. 我可以轻松地交换System32和SysWOW64的位置,但这是全局变量,而不是用户路径变量,并且需要重新启动才能使更改生效。
I will continue to experiment, but up to now the only 100% working solution is to keep the used " standard " BPLs into the platform output folder. 我将继续进行试验,但是到目前为止,唯一可行的解​​决方案是将使用过的“ 标准 ” BPL保留在平台输出文件夹中。

The exception text indicates that the call to LoadLibrary failed and GetLastError returned ERROR_MOD_NOT_FOUND . 异常文本指示对LoadLibrary的调用失败,并且GetLastError返回ERROR_MOD_NOT_FOUND There are two common explanations for this: 对此有两种常见的解释:

  1. The package file cannot be found by the DLL search. DLL搜索找不到包文件。 Perhaps the name was wrong, or the package is not in a location searched by the DLL search algorithm. 可能是名称错误,或者程序包不在DLL搜索算法搜索的位置。
  2. The package file can be found, but one of its dependencies cannot be found. 可以找到该软件包文件,但是找不到其依赖项之一。 For instance, perhaps the rtl package cannot be found. 例如,也许找不到rtl包。

Debug the issue using Dependency Walker. 使用Dependency Walker调试问题。 Use it in profile mode and it will tell you which module cannot be found. 在配置文件模式下使用它,它将告诉您找不到哪个模块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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