Einzelnen Beitrag anzeigen

Bodenseematze

Registriert seit: 10. Jul 2023
68 Beiträge
 
#1

Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 27. Feb 2024, 10:17
Hallo,

ich bin mir aktuell etwas unsicher, was die Speicherung und Weitergabe von Interface-Verweisen anbelangt.
Ist das erlaubt oder wird mir hier bei der Weiterreichung der "Zeiger" kaputt gemacht wg. Referenzzählung?

Ich versuche mal, das ganze hier (stark vereinfacht) darzustellen...

Ich habe Schnittstellendefinitionen, z.B.:
Delphi-Quellcode:
ITestGet = interface[ '{725D0235-8604-4E26-88E4-29223A3E6EB1}' ]
   function GetTestName() : String;
   property TestName : String
                                    read GetTestName;
end;


ITestSet = interface( ITestGet )[ '{2F54CC2F-70A8-4621-99C6-2B1CD5AE079F}' ]
   procedure SetTestName( const sName_ : String );
   property TestName : String
                                    write SetTestName;
end;


ITestImpl = interface( ITestGet )[ '{1C48CB92-1DA9-452E-9921-9B43A598715A}' ]
   procedure SetIfTestImpl( ifTestImpl_ : ITestImpl );
   function GetIfTestImpl() : ITestImpl;

   property IfTestImpl : ITestImpl
                                    read GetIfTestImpl
                                    write SetIfTestImpl;
end;

Dann habe ich folgende Klassen:
Delphi-Quellcode:
TMyBaseForm = class( TForm )
public
   constructor Create( owner_ : TComponent ); override;
   constructor CreateMe( owner_ : TComponent ); virtual;

   procedure SetIfTestImpl( ifTestImpl_ : ITestImpl ); virtual;
   function GetIfTestImpl() : ITestImpl; virtual;

   function GetIsIfTestImplSelf() : Boolean; virtual;

   property IfTestImpl : ITestImpl
                                    read GetIfTestImpl
                                    write SetIfTestImpl;

   property IsIfTestImplSelf : Boolean
                                    read GetIsIfTestImplSelf;

private
   _ifTestImpl : ITestImpl;
end;


//***************************************************************************
TMyOtherForm = class( TMyBaseForm )
published
   pbTest : TButton;


public
   constructor CreateMe( owner_ : TComponent ); override;
end;


//***************************************************************************
TMyMainBaseForm = class( TMyBaseForm, ITestImpl )
public
   constructor CreateMe( owner_ : TComponent ); override;

   procedure SetIfTestImpl( ifTestImpl_ : ITestImpl ); override;

   function GetTestName() : String; virtual;

   property TestName : String
                                    read GetTestName;
end;


//***************************************************************************
TMyMainForm = class( TMyMainBaseForm, ITestSet )
public
   constructor CreateMe( owner_ : TComponent ); override;

   function GetTestName() : String; override;
   procedure SetTestName( const sName_ : String ); virtual;

   property TestName : String
                                    read GetTestName
                                    write SetTestName;

private
   _sTestName : String;
end;

Hier die Implementierungen:
Delphi-Quellcode:
constructor TMyBaseForm.Create(
                                    owner_ : TComponent );
begin
   CreateMe( owner_ );
end;


constructor TMyBaseForm.CreateMe( owner_ : TComponent );
var
   ifTestImplMy : ITestImpl;
begin
   _ifTestImpl := nil;
   if ( Assigned(owner_) and Supports(owner_, ITestImpl, ifTestImplMy) ) then begin
      SetIfTestImpl( ifTestImplMy );
   end;
end;


procedure TMyBaseForm.SetIfTestImpl( ifTestImpl_ : ITestImpl );
begin
   _ifTestImpl := ifTestImpl_;
end;


function TMyBaseForm.GetIfTestImpl() : ITestImpl;
begin
  Result := _ifTestImpl;
end;


function TMyBaseForm.GetIsIfTestImplSelf() : Boolean;
var
  ifTestImplMy : ITestImpl;
begin
   Result := false;
   if ( Assigned(_ifTestImpl) ) then begin
      if ( Supports(Self, ITestImpl, ifTestImplMy) ) then begin
         if ( _ifTestImpl = ifTestImplMy ) then begin
            Result := true;
         end;
      end;
   end;
end;


//***************************************************************************
constructor TMyOtherForm.CreateMe( owner_ : TComponent );
var
   ifTestImplMy : ITestImpl;
begin
   inherited CreateMe( owner_ );

   pbTest := TButton.Create( Self );
   pbTest.Caption := 'Unknown';
   ifTestImplMy := IfTestImpl;
   if ( Assigned(ifTestImplMy) ) then begin
      pbTest.Caption := ifTestImplMy.TestName;
   end;
end;


//***************************************************************************
constructor TMyMainBaseForm.CreateMe( owner_ : TComponent );
var
   ifTestImplMy : ITestImpl;
begin
   inherited CreateMe( owner_ );
   ifTestImplMy := GetIfTestImpl();
   if ( NOT Assigned(ifTestImplMy) ) then begin
      SetIfTestImpl( nil );
   end;
end;


procedure TMyMainBaseForm.SetIfTestImpl( ifTestImpl_ : ITestImpl );
var
   ifTestImplMy : ITestImpl;
begin
   ifTestImplMy := ifTestImpl_;
   if ( NOT Assigned(ifTestImplMy) ) then begin
      Supports( Self, ITestImpl, ifTestImplMy );
   end;
   inherited SetIfTestImpl( ifTestImplMy );
end;


function TMyMainBaseForm.GetTestName() : String;
var
   ifTestImplMy : ITestImpl;
begin
   Result := EmptyStr;
   ifTestImplMy := GetIfTestImpl();
   if ( Assigned(ifTestImplMy) then begin
      if ( IsIfTestImplSelf ) then begin
         Result := Format( '%s.%s', [Classname, Name] );
      end
      else begin
         Result := ifTestImplMy.GetTestName();
      end;
   end;
end;


//***************************************************************************
constructor TMyMainForm.CreateMe( owner_ : TComponent );
begin
   inherited CreateMe( owner_ );
   _sTestName := EmptyStr;
end;


function TMyMainForm.GetTestName() : String;
begin
    if ( Length(_sTestName) > 0 ) then begin
       Result := _sTestName;
    end
    else begin
       Result := inherited GetTestName();
    end;
end;


procedure TMyMainForm.SetTestName( const sName_ : String );
begin
   _sTestName := sName_;
end;
In der Art wie TMyOtherForm gibt es ganz viele Klassen, so wie TMyMainForm gibt es normalerweise nur eine; wenn die MyOtherForm-Klassen instanziert werden, existiert die Instanz von TMyMainForm bereits und sie erhalten als Owner diese Instanz.

Ich habe jetzt das Problem, dass manchmal bei den Aufrufen von GetIfTestImpl bzw. dem Property IfTestImpl als Ergebnis nil zurück kommt, obwohl die interne Klassenvariable _ifTestImpl gesetzt ist.
Ich habe da bereits in der Methode eine Log-Ausgabe der Art Format( '%8.8X', [Integer(_ifTestImpl)] ) die zeigt eine Adresse an - wenn ich das ganze dann nach zurückkehren der Methode im Aufrufer mit dem zugewiesenen Ergebnis mache, kommt 0 als Ergebnis
--> deswegen meine Frage: ist es erlaubt, Interface-Zeiger in einer Klassenvariablen zu speichern und "herumzureichen"?

(das ganze wie immer bei mir für Delphi7 )
  Mit Zitat antworten Zitat