2016-04-20 12 views
4

Ich habe gelesen, dass, wenn eine Klasse eine Schnittstelle implementiert, es jetzt Referenz gezählt wird und sollte nicht verwalten seinen Speicher durch den Aufruf free.So implementieren Sie eine Schnittstelle in einem Delphi-Steuerelement

Wenn Sie jedoch ein benutzerdefiniertes Steuerelement erstellen und eine Schnittstelle implementieren, wie verhindern Sie dann, dass owner den Speicher verwaltet? Zum Beispiel, wenn Sie es zur Entwurfszeit auf ein Formular legen, wird die Referenzzählung und die Speicherverwaltung des Eigentümers kämpfen?

Danke für Ihre Zeit.

Antwort

6

Die Steuerelemente sind von diesem Verhalten ausgenommen, weil sie nicht von TInterfacedObject erben.
Als solche führen sie keine Referenzzählung durch, ihre Ref-Zählung bleibt bei -1 durch Entwurf *) stecken.

Alle Steuerelemente erben von TComponent, die wie folgt aussieht:

TComponent = class(TPersistent, IInterface, IInterfaceComponentReference) 

Die Referenzzählung in TComponent wie folgt aussieht:

function TComponent._AddRef: Integer; 
begin 
    if FVCLComObject = nil then Result := -1 
     // -1 indicates no reference counting is taking place 
    else Result := IVCLComObject(FVCLComObject)._AddRef; 
end; 

function TComponent._Release: Integer; 
begin 
    if FVCLComObject = nil then Result := -1 
    // -1 indicates no reference counting is taking place 
    else Result := IVCLComObject(FVCLComObject)._Release; 
end; 

*)Der Nachteil ist, dass wenn VCLComObject zugeordnet folgen sie der Referenzzählung des Objekts (die normalerweise nicht bei -1 feststeckt).
VCLComObject ist für die meisten Komponenten null.
Es wird nur für Komponenten-Wrapper verwendet, die von der IDE zum Umbrechen von COM-Objekten generiert werden.
See: TComponent.ComObject

So können Sie Schnittstellen zu Inhalt Ihres Herzens hinzuzufügen. Es wird ohne Probleme funktionieren, solange Sie sich daran erinnern, die Komponente zu befreien, wenn Sie fertig sind.

können Sie testen, ob ein Steuerreferenzzähler tut oder nicht durch Tests:

DoesNotRefCount:= Supports(MyObject, IInterfaceComponentReference) 
        and (TComponent(MyObject).VCLComObject = nil); 

Sie es nicht _AddRef auf Ihrem Objekt aufrufen zu testen, ob -1 zurückgibt, weil die Objekte brechen kann, die Verwendung zu tun Ref zählen.
Wenn Ihre ref gezählten Objekte bei 0 beginnt und Sie eine _AddRef gefolgt von einer _Release tun, werden Sie das Objekt zerstören, obwohl Delphi war gerade dabei, _AddRef zwei Anweisungen auf der ganzen Linie zu rufen.

Wenn Sie Ihre eigenen Objekte erstellen möchten, die nicht über einen Referenzzähler tun, kann es eine gute Idee sein, als auch eine Markierungsschnittstelle hinzu:

Abstieg Sie können von TSingletonImplementation
INoRefCounting = interface 
['{CAD60ADF-C49A-46FB-BB5A-CC54BD22C7EB}'] 
end; 

In neueren Delphi die zählt der Dummy No-Ref für Sie.
Bei älteren Abstieg Delphi von TObject (oder TWhatever) und implementieren, die nicht-ref Zählung wie folgt:

function TMyObject.QueryInterface(const IID: TGUID; out Obj): HResult; {stdcall;} 
begin 
    if GetInterface(IID, Obj) then Result := S_OK 
    else Result := E_NOINTERFACE; 
end; 

function TMyObject._AddRef: Integer; {stdcall;} 
begin 
    Result := -1; 
end; 

function TMyObject._Release: Integer; {stdcall;} 
begin 
    Result := -1; 
end; 

Schlussbemerkung
Wenn Sie 100% sicher, dass Ihre individuelle Steuerung tun nicht Bezug machen wollen Beim Zählen müssen Sie die Methoden _AddRef/_Release überschreiben, um die bedingte Referenzzählung basierend auf VCLComObject zu entfernen.

Warnung
Wenn die Lebensdauer Ihrer Kontrollen kurz ist und Sie immer noch Verweise auf Schnittstellen dieser Kontrollen hält länger dann werden Sie auf Probleme stoßen.
Wenn Sie darunter leiden, könnte es sinnvoll sein, den Methoden , _Release und Destroy Debugging-Code hinzuzufügen, wo Sie Referenzzahlen verfolgen und signalisieren, wenn die Refcounts Null zu spät oder zu früh erreicht.

+1

Und 'FVCLComObject' ist normalerweise Null für die meisten Komponenten. Es wird nur für Komponentenwrapper verwendet, die von der IDE zum Umschließen von COM-Objekten generiert werden (siehe 'TComponent.GetComObject()', das 'FVCLComObject' zuweist, obwohl' TComponent.VCLComObject' öffentlich ist, sodass Sie * ein COM-Objekt manuell als zuweisen können Gut). –

+0

Obwohl ein Schnittstellenobjekt dazu gebracht werden kann, "keine Referenzzählung durchzuführen" (d. H., Diese Zählung wird nicht beibehalten), werden die Aufrufe von ** AddRef ** und ** Release ** weiterhin auftreten. Im Ernst, Sie * können keine Schnittstellen hinzufügen und gehen über ** freie ** Objekte und sicher keine Probleme. Wenn Sie ein Objekt explizit ** freigeben **, das aktuelle Schnittstellenreferenzen zu diesem Objekt enthält, * * wird dies zu schwerwiegenden Problemen führen, wenn diese Referenzen ** Release ** d sind. Es ist besser, eine Referenzzählung zu halten und einen Bericht zu erstellen, wenn ein Objekt ** Free ** d mit einer Anzahl> 0 ist (was Sie * nicht * tun sollten). – Deltics

Verwandte Themen