delphi 组件是特定类-在BPL结构中不起作用

v64noz0r  于 2022-11-04  发布在  其他
关注(0)|答案(3)|浏览(139)

我正在将 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;

我已经考虑过比较类名,但这对后代不起作用。我们尝试过切换项目选项,如“发出运行时类型信息”,但这没有任何区别。
如何让这个工作?
谢谢你,谢谢你

qybjjes1

qybjjes11#

is运算符不能跨BPL(DLL)使用,原因如下:

  • 您正在检查的类是在它自己的单元文件中实现的。
  • 您构建BPL,链接单元,然后在BPL文件中创建RTTI部分。
  • 然后,构建EXE,链接单元,并在EXE文件中创建RTTI部分。
    现在:两个模块的class name相同,但is运算符用于检查相等性的RTTI不同,因此运算符返回FALSE
    **解决方案:**检查类名是否相等。
ct3nt3jp

ct3nt3jp2#

我在某个地方找到了这个,但它似乎与安东尼奥的回答有点矛盾。
当你使用软件包时,任何单元在内存中只有一个拷贝。一个Forms拷贝,一个SysUtils拷贝,一个System拷贝(大部分)、StdCtrls的一个副本等。所有与类相关的操作(如“is”和“as”操作符)依赖于类引用。类引用实际上只是地址。它们指向类内部布局的定义。(它们指向所谓的虚拟方法表VMT。)如果两个类指向相同的VMT --如果地址相等--则它们是相同的。当您在StdCtrls的EXE副本中定义了一个类,而在StdCtrls的DLL副本中定义了同一个类时,这些类实际上会有不同的地址。“is”和“as”操作符不适用于跨模块的类。但是当你使用包时,只有一个类的副本,保存在vcl70.bpl中,因此引用该包的所有模块将共享一个类定义。

kokeuurv

kokeuurv3#

正如Antonio Petricca所写的(谢谢!),不可能使用is操作符。现在我通过比较(祖先)类名实现了这个操作--我想分享代码:

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;

相关问题