2009-04-08 8 views
1

Ich habe eine Haupt-App und eine Typbibliothek enthält 2 COM-Objekte, eines ist IFile, eines ist IFiles. IFiles erstellt IFile und speichert sie in einem TLIST und verfügt über Standardmethoden wie Hinzufügen, Entfernen usw. Sowohl IFile als auch IFiles sind TAutoObject.Irgendwie COM Objektinstanz wird verloren

"Add" -Methode in IFiles funktioniert gut, es erstellt einfach IFile-Objekt [Code 1], und fügt es zu TList. Problem ist, wenn die Objektinstanz auf sehr seltsame Weise verloren geht. siehe [Code 2]

[Code 1]

function IFiles.Add(AFilename: String): IFile; 
begin 
    Result := CoIFile.Create; 
    Result.Filename := AFilename; 
    // ShowMessage(IntToStr(Result._AddRef)); 
    fFiles.Add(@Result); 
end; 

Im Haupt app Ich habe Testcode wie diese. [Code 2]

var 
    i: Integer; 
    f: IFile; 
    Files: IFiles; 
begin 
    Files := CoTIFile.Create; 
    for i:= 1 to 4 do 
    begin 
    // Create a dummy file object 
    f := Files.Add('Filename ' + IntToStr(i)); 
    f._AddRef; // Not sure if AddRef works like this 
    // Prints out the last file 
    Memo1.Lines.Add(Files.Files[i-1].Filename); 
    end; 

    for i:= 0 to Files.Count-1 do 
    begin 
    f := Files.Files[i]; 
    // F is nil at all time. 
    if (f<>nil) then Memo1.Lines.Add(f.Filename); // ! No print out. 
    end; 
end; 

Vom 2. Schleife, obwohl fFiles.Count = 4, aber alle Inhalte verloren haben. Benötige ich eine zusätzliche Behandlung in IFile, um mit AddRef und Release umzugehen? oder wie IFiles.Add Methode, die ich schrieb, falsch ist?

Antwort

8

Verwenden Sie TInterfaceList anstelle von TList, um die IFile-Instanzen zu speichern. Dies kann Ihr Problem lösen.

+0

Aha. TInterfaceList. – Darkerstar

0

Die COM-Objekte werden automatisch freigegeben, wenn keine Referenzen darauf vorhanden sind. In Code 1 wird das COM-Objekt am "end" -Auftrag freigegeben.

Ich denke, Sie müssen ein Wrapper-Objekt erstellen, und das Wrapper-Objekt ist, was Sie Dateien hinzufügen.

In sory habe ich nicht die Zeit, um ein Beispiel zu erstellen.

1

Das Problem in Ihrem ursprünglichen Code war, dass Sie ein IFileZeiger in die Liste wurden hinzugefügt, aber wenn Sie einen Wert aus der Liste später lesen, können Sie den Zeiger direkt an einem anderen IFile Variablen zugewiesen. Sie hatten also war im Wesentlichen ein PIFile Wert in einer IFile Variable gespeichert. In Delphi können Sie normalerweise den Typ Pointer jedem zeigerähnlichen Typ zuweisen, einschließlich der Schnittstellen.

ursprünglichen Code zu beheben, können Sie den zweiten Blick etwas schreiben müssten:

var 
    p: Pointer; 

for i := 0 to Pred(Files.Count) do begin 
    p := Files.Files[i]; 
    if not Assigned(p) then 
    continue; 
    f := IFile(p^); 
    if not Assigned(f) then 
    continue; 
    Memo1.Lines.Add(f.Filename); 
end; 

Sie Recht hatten f._AddRef in Ihrem ersten Schleife zu nennen. Wenn IFiles.Add zurückkehrt, ist der Referenzzähler auf dem Ergebnis 1, da der in der Schleife gespeicherte Wert ein Zeiger ist, nicht die tatsächliche Referenz. Sie müssen die Referenzzählung erhöhen, da f für andere Werte wiederverwendet wird. Da die Referenz, die Sie manuell zählen, in der FFiles Liste gespeichert ist, wäre es besser, _AddRef innerhalb IFiles.Add aufzurufen, anstatt zu warten, bis es zurückkehrt.

Wenn Sie die Liste löschen oder Elemente aus der Liste entfernen, müssen Sie _Release für alle Schnittstellenreferenzen aufrufen.

Aber Toby's answer gibt die bessere Idee: Verwenden Sie TInterfaceList, um eine Liste von Schnittstellen zu speichern. TList ist einfach nicht für die Aufgabe allein geeignet.

Ein letzter Ratschlag: Das Präfix "I" auf Namen wird verwendet, um Schnittstelle Typen zu bezeichnen. Schnittstellen haben keine eigenen Methodenimplementierungen.Sie haben die Implementierung von IFiles.Add gezeigt, also ist IFiles eindeutig kein Schnittstellentyp. Es sollte stattdessen TFiles oder vielleicht TFileList genannt werden.

Verwandte Themen