![](/img/trans.png)
[英]Compile Delphi component package (bpl) for different Delphi versions
[英]Component is specific class - does not work in BPL structure
我正在将 Delphi 软件从 Delphi 6 (2001) 升级到 Delphi 11 Alexandria。
该软件包含许多 BPL,但此代码无法正常工作。 当检查来自 BPL 的组件是否是 TIBQuery 时, is 命令没有返回 True,尽管它确实是。
procedure LoadDLLAndPassDatabaseConnection(const DLLName: string);
var
PackageHandle: HMODULE;
ServiceModule: TMyServiceModule;
I: Integer;
Component: TComponent;
begin
PackageHandle := LoadPackage(PChar(DLLName));
ServiceModule := TMyServiceModule(GetProcAddress(hInst,'GetServiceModule'));
if Assigned(ServiceModule) then
begin
for I:=0 to ServiceModule.ComponentCount - 1 do
begin
Component := ServiceModule.Components[I];
// This component is declared in another bpl.
// It really is an TIBQuery, but the following if never returns True...
// (Evaluating Component.ClassName results in 'TIBQuery')
if Component is TIBQuery then
begin
// this is never executed...
TIBQuery(Component).Database := GetDatabase;
end;
end;
end;
end;
我已经考虑过比较类名,但这不适用于后代。 我们尝试切换项目选项,例如“Emit runtime type information”,但这没有任何区别。
如何让这个工作?
谢谢!
is
运算符不能跨 BPL (DLL) 工作,原因如下:
现在:两个模块的class name
相同,但是is
运算符用于检查相等性的 RTTI不同,因此运算符返回FALSE !
解决方案:检查 class 名称是否相等。
正如 Antonio Petricca 所写(谢谢),不可能使用is
运算符。 我现在通过比较(后代)class 名称来实现这一点 - 我想分享代码:
function IsSameClassOrAncestor(const ClazzToCheck: TClass; const Clazz: TClass): Boolean;
begin
Result := SameText(ClazzToCheck.ClassName, Clazz.ClassName);
if not Result and not SameText(ClazzToCheck.ClassName, 'TObject') then
begin
Result := IsSameClassOrAncestor(ClazzToCheck.ClassParent, Clazz);
end;
end;
这样,我可以检查如下:
if IsSameClassOrAncestor(Component, TIBQuery)
begin
// The code is now executed correctly, also for descendants
TIBQuery(Component).Database := GetDatabase;
end;
我在某个地方找到了这个,但它似乎与 Antionio 的回答有点矛盾。
使用包时,memory 中的任何单元都只有一个副本。 Forms 一份,SysUtils 一份,System 一份(嗯,大部分),StdCtrls 一份等。所有与类相关的操作,例如“is”和“as”运算符,都依赖于 class参考。 Class 引用实际上只是地址。 它们指向类内部布局的定义。 (它们指向所谓的虚拟方法表,即 VMT。)如果两个类指向同一个 VMT——如果地址相等,则它们是相同的。 当您在 EXE 的 StdCtrls 副本中定义了 class 并且在 DLL 的 StdCtrls 副本中定义了相同的 class 时,这些类实际上将具有不同的地址。 “is”和“as”运算符不适用于跨模块类。 但是,当您使用包时,只有一份 class 副本保存在 vcl70.bpl 中,因此所有引用该 package 的模块将共享一个 class 定义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.