【问题标题】:Dynamically loading BPL fails in LoadLibrary在 LoadLibrary 中动态加载 BPL 失败
【发布时间】:2016-10-03 15:57:21
【问题描述】:

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


Project LoadPackageTest.exe 引发异常类 EPackageError,并显示消息“无法加载包“此处的真实路径”\TestBplPackage.bpl。 找不到指定的模块'。


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

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

  • 如果在同一台 Win 10 PC 上使用 Delphi 2007 Enterprise 编译,相同的项目组可以正常工作(我不得不从头开始重新创建)

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

实际上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\
Win32Win64 子文件夹要么在应用程序和测试 BPL 所在的文件夹中,要么在相关的 System32SysWOW64 文件夹中。

没有上述内容,尽管
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 平台编译,我会收到以下错误消息:
应用程序无法正确启动 (0xc000007b)
这是因为 32 位应用程序尝试加载 64 位 BPL。

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

【问题讨论】:

  • 我无法复制 - 创建了一个新的 BPL 项目,复制、粘贴、构建;制作了一个新的 VCL 应用程序,添加了按钮和 opendialog,复制、粘贴、构建。运行应用程序,选择 BPL,在消息框中看到当前时间。 D10-Win7 上的西雅图。
  • @J... 你的 Win 7 是 64 位吗?您是否尝试过 32 位和 64 位目标平台?
  • 是的,64 位操作系统。我只为 32 位构建 - 你说它不适用于任何一个平台,所以我认为无论问题是什么,它都与平台无关。
  • 将路径恢复为默认值。阅读有关文件系统重定向的信息。然后将必要的依赖包放在 eve 目录中。或者干脆停止使用包。
  • 不要将文件放入系统目录。它们适用于系统。

标签: delphi delphi-10-seattle bpl delphi-10.1-berlin


【解决方案1】:

异常文本表明对LoadLibrary 的调用失败并且GetLastError 返回ERROR_MOD_NOT_FOUND。对此有两种常见的解释:

  1. DLL 搜索找不到包文件。可能名称错误,或者包不在 DLL 搜索算法搜索到的位置。
  2. 可以找到包文件,但找不到它的依赖项之一。例如,可能找不到 rtl 包。

使用 Dependency Walker 调试问题。在配置文件模式下使用它,它会告诉您找不到哪个模块。

【讨论】:

  • 谢谢你,大卫!但我从 Dependency Walker 得到以下信息:LoadLibraryW("C:\rumen\work\dX\Packages\TestBplPackage.bpl") 从地址 0x000000000043ED00 的“LOADPACKAGETEST.EXE”调用。在地址 0x0000000004FB0000 加载“TESTBPLPACKAGE.BPL”。成功挂接模块。 LoadLibraryW("C:\rumen\work\dX\Packages\TestBplPackage.bpl") 返回 NULL。错误:找不到指定的模块 (126)。所有东西(.exe、.bpl、.dll)都在同一个文件夹中。在 D2007 上,它在相同条件下进行了测试。而我把D2007项目组带进了D10……
  • 错误信息实在是无可争辩。在我的回答中可以找到唯一合理的解释。显然找不到模块或其依赖项之一。现在你必须找出原因。
  • (1)的一个特殊情况是工作目录不是预期的?或者Delphi是否也强制检查与exe相同的目录以进行动态加载?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-03
相关资源
最近更新 更多