Also ich hab das auch mit Delphi2007 getestet. Das AddRef brauchst du weil die InterfaceListe zerstört wird aber du immernoch über Data auf das Object zugreifen willst.
So gehts:
Delphi-Quellcode:
type
IDataObject = interface(IInterface)
['{C94DCAC7-CA42-45D3-95D7-9BC321BA2E2A}']
procedure Delete;
end;
IAccountData = interface(IInterface)['{DA626905-CB35-4474-B353-9F8E973709AA}']
function GetId: Integer;
procedure SetId(_Id: Integer);
property ID: Integer read Getid write SetId;
end;
TAccountData = class(TInterfacedObject, IAccountData)
protected
FID: Integer;
function Getid: Integer;
procedure SetId(_Id: Integer);
public
destructor Destroy; override;
end;
TAccountDataExtend = class(TAccountData, IDataObject)
public
procedure Delete;
end;
procedure TForm9.ListViewMainClick(Sender: TObject);
var
obj: IInterface;
obj3: IDataObject;
begin
inherited;
if ListViewMain.ItemIndex >= 0 then begin
obj := IInterface(ListViewMain.Selected.Data);
if Succeeded(obj.QueryInterface(IDataObject, obj3)) then begin
obj3.Delete; //Funktion siehe unten
end;
end;
end;
procedure TForm9.ListViewMainDeletion(Sender: TObject; Item: TListItem);
begin
IInterface(Item.Data)._Release;
end;
procedure TForm9.Refresh;
var
tmp: IAccountData;
i: Integer;
item: TListItem;
x: TInterfaceList;
begin
//Vorgängig Listview aufräumen, Objekte zerstören, Interface Releasen
x := TInterfaceList.Create;
try
GetAllAccounts(x); //Siehe Funktion unten
for i := 0 to x.Count - 1 do begin
if Succeeded(x[i].QueryInterface(IAccountData, tmp)) then begin
item := ListViewMain.Items.Add;
item.Caption := IntToStr(tmp.ID); //Zeigt korrekte ID an
item.Data := Pointer(tmp);
end;
end;
finally
FreeAndNil(x); //Ich nehme an die InterfaceList zerstört die Objekte nicht
end;
end {LoadListView};
procedure TForm9.Button1Click(Sender: TObject);
begin
Refresh;
end;
procedure TForm9.GetAllAccounts(_o: TInterfaceList);
var
tmp: IAccountData; //Oder IInterface?
i: integer;
begin
for i := 0 to 4 do begin
tmp := TAccountDataExtend.Create;
tmp.ID := i;
tmp._AddRef;
_o.Add(tmp);
end;
end {GetAllAccounts};
//----------------- TAccountDataExtend
procedure TAccountDataExtend.Delete;
begin
ShowMessage(IntToStr(FID));
end {Delete};
{ TAccountData }
destructor TAccountData.Destroy;
begin
MessageBox(0,'del',nil,0);
inherited;
end;
function TAccountData.Getid: Integer;
begin
Result := Fid;
end;
procedure TAccountData.SetId(_Id: Integer);
begin
Fid := _id;
end;
hab auch mal nen destructor eingebaut, damit du siehst wann das object zerstört wird (ohne _addref schon beim zerstören der InterfaceList). Und damit du kein Speicherleck hast musst du auch wieder _Release aufrufen.
Im grunde brignt das das nte viel bei dem Beispiel weil du ne Sonderbehandlung bei Data brauchst. Dann kannst auch auf interfaces verzichten und gleich selbst freigeben (es sei denn es wird ein externes Modul wo du mit interfaces drauf zugreifen willst).