首页 文章

在LoadLibrary中动态加载BPL失败

提问于
浏览
2

我想在Delphi 10 Seattle(Update 1)或Delphi 10.1 Berlin项目(Enterprise版本)中动态加载BPL模块 . 但LoadPackage函数失败并显示消息(在32位和64位目标平台上):


Project LoadPackageTest.exe raised exception class EPackageError with message 'Can't load package "real path here"\TestBplPackage.bpl. The specified module could not be found'.


我的开发平台是Windows 10 Pro 64位 .

我确信传递的文件名是正确的(它包含完整路径) . 我到目前为止做了什么:

  • 如果使用Delphi 2007 Enterprise进行编译,同一个项目组可以毫无问题地工作(我必须从头开始重新创建) - 在同一台Win 10 PC上

  • 如果我加载标准.DLL - 它正确加载,我可以在D2007,D10和D10.1中调用函数(适用于D10和D10.1上的32位和64位目标) .

实际上,LoadPackage调用SafeLoadLibrary,它调用LoadLibrary(所有这些过程都在System.SysUtils中 .

我使用和不使用Run Time包编译了测试可执行文件 . 代码如下:

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%环境变量中 . 它没有找到 RTL 包 .


如果应用程序依赖于%PATH%变量来查找必要的BPL,则会有一个易于解释的副作用 . 因为我有C:\ Windows \ SysWOW64; C:\ WINDOWS \ system32; C:\ WINDOWS
在%PATH%变量中,如果我使用运行时包编译Win32平台,我收到以下错误消息:
The application was unable to start correctly (0xc000007b)
这是因为32位应用程序试图加载64位BPL .

我可以轻松地交换System32和SysWOW64的位置,但这是全局的,而不是用户路径变量,需要重新启动才能使更改生效 .
我将继续进行实验,但到目前为止,唯一100%可行的解决方案是将使用过的“标准”BPL保存到平台输出文件夹中 .

1 回答

  • 4

    异常文本表示对 LoadLibrary 的调用失败, GetLastError 返回 ERROR_MOD_NOT_FOUND . 对此有两种常见的解释:

    • DLL搜索无法找到包文件 . 可能名称错误,或者包不在DLL搜索算法搜索的位置 .

    • 可以找到包文件,但找不到其中一个依赖项 . 例如,可能无法找到 rtl 包 .

    使用Dependency Walker调试问题 . 在配置文件模式下使用它,它将告诉您无法找到哪个模块 .

相关问题