在 LoadLibrary 中动态加载 BPL 失败
Dynamically loading BPL fails in LoadLibrary
我想在 Delphi 10 Seattle(更新 1)或 Delphi 10.1 Berlin 项目(企业版)中动态加载 BPL 模块。但是 LoadPackage 函数失败并显示消息(在 32 位和 64 位目标平台上):
项目 LoadPackageTest.exe 引发异常 class EPackageError,消息为“无法加载包 "real path here"\TestBplPackage.bpl。
找不到指定的模块'。
我的开发平台是Windows10 Pro 64位
我确定传递的文件名是正确的(它包含完整路径)。
我到目前为止所做的事情:
如果使用 Delphi 2007 Enterprise 在同一台 Win 10 PC 上编译,同一个项目组可以正常工作(我不得不从头开始重新创建它)
如果我加载标准 .DLL - 它被正确加载并且我可以调用 D2007、D10 和 D10.1 中的函数(适用于 D10 和 D10.1 上的 32 位和 64 位目标) .
其实LoadPackage调用的是SafeLoadLibrary,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;
有人试过类似的东西吗?
避免从项目管理器树的 "Contains" 节点删除单元 - Delphi 10 和 10.1 崩溃...
编辑 1:它在某些条件下有效
感谢大卫的回答,我取得了一些进展:
当相关
的内容正常工作
C:\Program Files (x86)\Embarcadero\Studio.0\Redist\
Win32 或 Win64 子文件夹要么在应用程序和测试 BPL 所在的文件夹中,要么在相关的 System32 或 SysWOW64 文件夹。
如果没有上述内容,我无法使其正常工作,尽管
C:\Program Files (x86)\Embarcadero\Studio.0\bin 和
C:\Program Files (x86)\Embarcadero\Studio.0\bin64
在 %PATH% 环境变量中。它没有找到 RTL 包。
如果应用程序依赖 %PATH% 变量来查找必要的 BPL,则有一个很容易解释的副作用。因为我有 C:\Windows\SysWOW64;C:\WINDOWS\system32;C:\WINDOWS
在 %PATH% 变量中,如果我使用 运行 时间包为 Win32 平台编译,我会收到以下错误消息:
应用程序无法正确启动(0xc000007b)
这是因为 32 位应用程序试图加载 64 位 BPL。
我可以轻松交换 System32 和 SysWOW64 的位置,但这是全局的,而不是用户路径变量,需要重新启动才能使更改生效。
我会继续试验,但到目前为止,唯一 100% 可行的解决方案是将使用过的“standard”BPL 保存到平台输出文件夹中.
异常文本表明对 LoadLibrary
的调用失败并且 GetLastError
返回了 ERROR_MOD_NOT_FOUND
。对此有两种常见的解释:
- DLL 搜索找不到包文件。可能名称有误,或者包不在 DLL 搜索算法搜索到的位置。
- 可以找到包文件,但找不到其依赖项之一。例如,可能找不到
rtl
包。
使用 Dependency Walker 调试问题。在配置文件模式下使用它,它会告诉你找不到哪个模块。
我想在 Delphi 10 Seattle(更新 1)或 Delphi 10.1 Berlin 项目(企业版)中动态加载 BPL 模块。但是 LoadPackage 函数失败并显示消息(在 32 位和 64 位目标平台上):
项目 LoadPackageTest.exe 引发异常 class EPackageError,消息为“无法加载包 "real path here"\TestBplPackage.bpl。 找不到指定的模块'。
我的开发平台是Windows10 Pro 64位
我确定传递的文件名是正确的(它包含完整路径)。 我到目前为止所做的事情:
如果使用 Delphi 2007 Enterprise 在同一台 Win 10 PC 上编译,同一个项目组可以正常工作(我不得不从头开始重新创建它)
如果我加载标准 .DLL - 它被正确加载并且我可以调用 D2007、D10 和 D10.1 中的函数(适用于 D10 和 D10.1 上的 32 位和 64 位目标) .
其实LoadPackage调用的是SafeLoadLibrary,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;
有人试过类似的东西吗?
避免从项目管理器树的 "Contains" 节点删除单元 - Delphi 10 和 10.1 崩溃...
编辑 1:它在某些条件下有效
感谢大卫的回答,我取得了一些进展:
当相关
的内容正常工作
C:\Program Files (x86)\Embarcadero\Studio.0\Redist\
Win32 或 Win64 子文件夹要么在应用程序和测试 BPL 所在的文件夹中,要么在相关的 System32 或 SysWOW64 文件夹。
如果没有上述内容,我无法使其正常工作,尽管
C:\Program Files (x86)\Embarcadero\Studio.0\bin 和
C:\Program Files (x86)\Embarcadero\Studio.0\bin64
在 %PATH% 环境变量中。它没有找到 RTL 包。
如果应用程序依赖 %PATH% 变量来查找必要的 BPL,则有一个很容易解释的副作用。因为我有 C:\Windows\SysWOW64;C:\WINDOWS\system32;C:\WINDOWS
在 %PATH% 变量中,如果我使用 运行 时间包为 Win32 平台编译,我会收到以下错误消息:
应用程序无法正确启动(0xc000007b)
这是因为 32 位应用程序试图加载 64 位 BPL。
我可以轻松交换 System32 和 SysWOW64 的位置,但这是全局的,而不是用户路径变量,需要重新启动才能使更改生效。
我会继续试验,但到目前为止,唯一 100% 可行的解决方案是将使用过的“standard”BPL 保存到平台输出文件夹中.
异常文本表明对 LoadLibrary
的调用失败并且 GetLastError
返回了 ERROR_MOD_NOT_FOUND
。对此有两种常见的解释:
- DLL 搜索找不到包文件。可能名称有误,或者包不在 DLL 搜索算法搜索到的位置。
- 可以找到包文件,但找不到其依赖项之一。例如,可能找不到
rtl
包。
使用 Dependency Walker 调试问题。在配置文件模式下使用它,它会告诉你找不到哪个模块。