簡體   English   中英

組件是特定的 class - 在 BPL 結構中不起作用

[英]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 在其自己的單元文件中實現。
  • 您構建 BPL,鏈接單元,然后在 BPL 文件中創建一個 RTTI 部分。
  • 然后,您構建 EXE,鏈接單元,並在 EXE 文件中創建一個的 RTTI 部分。

現在:兩個模塊的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM