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
)