简体   繁体   English

组件是特定的 class - 在 BPL 结构中不起作用

[英]Component is specific class - does not work in BPL structure

I am upgrading Delphi software from Delphi 6 (2001) to Delphi 11 Alexandria.我正在将 Delphi 软件从 Delphi 6 (2001) 升级到 Delphi 11 Alexandria。

This software consists of many BPL's, but this code is not working properly.该软件包含许多 BPL,但此代码无法正常工作。 The is command is not returning True, when checking if the component from a BPL is an TIBQuery - although it really is.当检查来自 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;

I already considered to compare classnames, but this does not work for descendants.我已经考虑过比较类名,但这不适用于后代。 And we tried toggling project options such as "Emit runtime type information", but that's not making any difference.我们尝试切换项目选项,例如“Emit runtime type information”,但这没有任何区别。

How to get this working?如何让这个工作?

Thank you!谢谢!

The is operator does not work across BPLs (DLLs) for the following reason: is运算符不能跨 BPL (DLL) 工作,原因如下:

  • The class you are inspecting is implemented inside its own unit file.您正在检查的 class 在其自己的单元文件中实现。
  • You build the BPL, link the unit, and a RTTI section is created inside the BPL file.您构建 BPL,链接单元,然后在 BPL 文件中创建一个 RTTI 部分。
  • Then, you build the EXE, link the unit, and a new RTTI section is created inside the EXE file.然后,您构建 EXE,链接单元,并在 EXE 文件中创建一个的 RTTI 部分。

Now: the class name is the same for the two modules, but the RTTI, used by the is operator to check equality, are different , so the operator returns FALSE !现在:两个模块的class name相同,但是is运算符用于检查相等性的 RTTI不同,因此运算符返回FALSE

Solution: check equality againts class name.解决方案:检查 class 名称是否相等。

As Antonio Petricca wrote (thank you,), it's not possible to use the is operator.正如 Antonio Petricca 所写(谢谢),不可能使用is运算符。 I now have implemented this by comparing (descendant) class names - I want to share the code:我现在通过比较(后代)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;

This way, I can check this as follows:这样,我可以检查如下:

if IsSameClassOrAncestor(Component, TIBQuery)
begin
  // The code is now executed correctly, also for descendants
  TIBQuery(Component).Database := GetDatabase;
end;

I found this somewhere, but it seems to contradict Antionio's answer a bit.我在某个地方找到了这个,但它似乎与 Antionio 的回答有点矛盾。

When you use packages, there is only ever one copy of any unit in memory.使用包时,memory 中的任何单元都只有一个副本。 One copy of Forms, one copy of SysUtils, one copy of System (well, most of it), one copy of StdCtrls, etc. All class-related operations, such as the "is" and "as" operators, rely on class references. Forms 一份,SysUtils 一份,System 一份(嗯,大部分),StdCtrls 一份等。所有与类相关的操作,例如“is”和“as”运算符,都依赖于 class参考。 Class references are actually just addresses. Class 引用实际上只是地址。 They point to definitions for the layouts of the classes' internals.它们指向类内部布局的定义。 (They point to what's called the virtual-method table, the VMT.) Two classes are the same if they point to the same VMT -- if the addresses are equal. (它们指向所谓的虚拟方法表,即 VMT。)如果两个类指向同一个 VMT——如果地址相等,则它们是相同的。 When you have a class defined in the EXE's copy of StdCtrls and the same class defined in a DLL's copy of StdCtrls, those classes will really have different addresses.当您在 EXE 的 StdCtrls 副本中定义了 class 并且在 DLL 的 StdCtrls 副本中定义了相同的 class 时,这些类实际上将具有不同的地址。 The "is" and "as" operators won't work with cross-module clases. “is”和“as”运算符不适用于跨模块类。 But when you use packages, there is only one copy of the class, kept in vcl70.bpl, so all modules that reference that package will share a single class definition.但是,当您使用包时,只有一份 class 副本保存在 vcl70.bpl 中,因此所有引用该 package 的模块将共享一个 class 定义。

暂无
暂无

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

相关问题 为不同的Delphi版本编译Delphi组件包(bpl) - Compile Delphi component package (bpl) for different Delphi versions Delphi FMX RTL270.bpl 错误与可视组件 TbackendEndpoint - Delphi FMX RTL270.bpl error with visual component TbackendEndpoint Delphi XE2无法获得BPL插件工作 - Delphi XE2 Cannot get BPL plugin work 使dclsockets70.bpl的先前版本可用于delphi - Getting previous version of dclsockets70.bpl to work for delphi 组件TSomething无法通过包something_design.bpl注册,因为它已经被包stuff_design.bpl注册。 - Component TSomething can't be registered by package something_design.bpl because it has already been registered by package something_design.bpl.? rtl170.bpl模块中的EReadError异常-RichEdit1.Zoom:属性缩放不存在 - Exception EReadError in module rtl170.bpl - RichEdit1.Zoom: Property Zoom does not exists Delphi DLL Project在自定义BPL中找不到单位,除非“与运行时程序包链接”为True - Delphi DLL Project does not find unit in custom BPL except when “Link with Runtime Packages” is True 将BPL与在其他BPL中实现的组件一起安装 - Install BPL with components implemented in an other BPL in Delphi - 如果没有创建类,为什么这个函数有效? - Delphi - why does this function work if the class is not created? 为什么脚本不起作用/ Web浏览器(控件/组件)中未按下按钮? - Why the script does not work / the button is not pressed in the web browser (control/component)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM