Einzelnen Beitrag anzeigen

brechi

Registriert seit: 30. Jan 2004
823 Beiträge
 
#11

AW: Data-Pointer in Interfacevariable casten

  Alt 15. Jul 2010, 19:51
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).
  Mit Zitat antworten Zitat