![]() |
TWinControl via TInterfacedObject via TInterfacedPersistent
Meine Classe
Aktuell..
Delphi-Quellcode:
Ich verwende keine WinControls daher frage ich mich was besser wäre das Aktuelle oder diese hier.
TOnSessionStateEvent = procedure(Sender: TCustomAudioVolume; NewState: integer) of object;
TCustomAudioVolume = class(TWinControl) // end; TAudioVolume = class(TCustomAudioVolume, IAudioSessionEvents, IMMNotificationClient, IAudioSessionNotification, IAudioEndpointVolumeCallback) begin // .. Inhalt jetzt egal end TInterfacedObject..
Delphi-Quellcode:
TInterfacedPersistent..
TOnSessionStateEvent = procedure(Sender: TObject; NewState: integer) of object;
TAudioVolume = class(TInterfacedObject, IAudioSessionEvents, IMMNotificationClient, IAudioSessionNotification, IAudioEndpointVolumeCallback)
Delphi-Quellcode:
welche vor bzw.. Nachteile würden sich dadurch ergeben?
TOnSessionStateEvent = procedure(Sender: TPersistent; NewState: integer) of object;
TAudioVolume = class(TInterfacedPersistent, IAudioSessionEvents, IMMNotificationClient, IAudioSessionNotification, IAudioEndpointVolumeCallback) wie sieht das dann mit create, inherited und Konsorte aus. Ja bei TObject, TPersistent müsste ich Create ändern nur welche gesamt Auswirkung hätten diese Änderungen und sind sie sinnvoll.
Delphi-Quellcode:
public
constructor Create; reintroduce;
Delphi-Quellcode:
constructor TAudioVolume.Create();
inherited Create(); gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Wenn du TWinControl nicht brauchst, macht es auch keinen Sinn davon abzuleiten.
Wenn du Interfaces benutzt, dann am besten richtig mit Referenzzählung, sprich mit TInterfacedObject. Und auch so, dass du nur über Interfaces mit den Objekten arbeitest und nie über Objektreferenzen. Denn nur so kannst du ausschließen, dass die Referenzzählung das Objekt freigibt, du aber noch eine Objektreferenz offen hast oder umgekehrt. TInterfacedPersistent macht dabei keinen Sinn, denn es schaltet die Referenzzählung aus bzw. implementiert diese nicht. |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Ich dachte eigentlich es hätte irgendwelche Vorteile.
Bisher kann ich keinen erkennen bei deiner Aussage. Eher Nachteile falls jemand diese Klasse später mit WinControls nutzen möchte. Vielleicht dann lieber gar nichts ändern. Danke. gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
Wenn ich tmpAudioVolume.Free aufrufe dann kracht es mit invalid Pointer weil noch 3 refcounter offen sind. (TInterfacedObject) Habe es nur testweise mal versucht. gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Ich denke, ich würde hier komplett anders vorgehen. Deine Komponente
Delphi-Quellcode:
muss die Interfaces
TAudioVolume
Delphi-Quellcode:
doch gar nicht öffentlich implementieren. Du könntest dafür eine weitere (private) Klasse in der gleichen Unit anlegen und Befehle von
IAudioSessionEvents, IMMNotificationClient, IAudioSessionNotification, IAudioEndpointVolumeCallback
Delphi-Quellcode:
an eine Instanz davon weiterleiten bzw. die Callbacks von der Instanz zur
TAudioVolume
Delphi-Quellcode:
Komponente. Also eine Art Proxy sozusagen. Von dem Proxy erstellt du dann pro
TAudioVolume
Delphi-Quellcode:
Instanz ebenfalls eine Instanz und gibst diese im Destructor frei (
TAudioVolume
Delphi-Quellcode:
besitzt also die Proxy Instanz).
TAudioVolume
Delphi-Quellcode:
selbst kannst du dann z.B. einfach von
TAudioVolume
Delphi-Quellcode:
ableiten.
TObject
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
Wir sind davon abgekommen weil es nicht möglich war die Interface in OnSessionCreate und Konsorte mit PostMessage weiterzuleiten. Es ist auch keine Komponente sondern nur eine Klasse TAudioVolume. TObject habe ich versucht dann kracht es gewaltig invalid pointer ;) sagte ich schon. gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
Extrahiere die wichtigsten Methoden von TAudioVolume in ein IAudioVolume und füge es deiner Klasse hinzu:
Delphi-Quellcode:
TAudioVolume = class(TInterfacedObject, IAudioVolume, IAudioSessionEvents, IMMNotificationClient, IAudioSessionNotification, IAudioEndpointVolumeCallback)
Delphi-Quellcode:
//Erzeugen in der Anwendung dann nur über:
var tmpAudioVolume: IAudioVolume; begin tmpAudioVolume := TAudioVolume.Create; ... end; |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
Ich denke werde es erst mal so belassen wie es ist. Ich muss die Kontrolle darüber haben das Object selbst freigeben zu können. Es war auch nur mal ein Test um zu sehen welche Auswirkungen das hat, haben könnte. Ich denke auch das der Mixer jetzt fertig ist das mit den kleinen Problem was die Session angeht liegt an der Audio Core selbst (Win7) die entläd diese manchmal nicht oder schickt kein Event. Ist der Grund warum ich jetzt doch über die Prozesse gehen muss. gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
Delphi-Quellcode:
type
TOnSessionCreate = procedure(...) of Object; TAudioVolume = class(TObject) strict private FProxy: TAudioVolumeProxy; strict protected FOnSessionCreate: TOnSessionCreate; public property OnSessionCreate: TOnSessionCreate read FOnSessionCreate write FOnSessionCreate; ... TAudioVolumeProxy = class(TInterfacedObject, IAudioVolume, IAudioSessionEvents, IMMNotificationClient, IAudioSessionNotification, IAudioEndpointVolumeCallback) strict prviate FOwner: TAudioVolume; strict private procedure OnSessionCreate(...); ... constructor TAudioVolume.Create; begin inherited Create; FProxy := TAudioVolumeProxy.Create(Self); end; destructor TAudioVolume.Free; begin FProxy.Free; inherited Destroy; end; procedure TAudioVolumeProxy.OnSessionCreate(...) begin if Assigned(FOwner.FOnSessionCreate) then begin FOwner.FOnSessionCreate(...); end; end;
Delphi-Quellcode:
selbst hat hierbei praktisch gar keine eigene Funktionalität, sondern dient nur als Schnitstelle (Proxy sollte man vermutlich in Implementation oder sowas umbenennen).
TAudioVolume
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
@Zacherl
Mit der Anleitung kann man allerdings nur Schiffbruch erleiden, oder? Wo ist denn jetzt der Unterschied zu der vorherigen Situation? - TAudioVolume erzeugen - Über TAudioVolumeProxy eine Interface-Instanz weiterreichen - TAudioVolume freigeben - Es knallt, wenn die Interface-Instanz auf nil gesetzt wird. Dieses Verhalten hatte der TE schon selber gebaut und auch noch mit viel weniger Code. Zitat:
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Um was es mir ging..
Ist die Unterschiede zu erfahren was ist besser, schneller bzw. Korrekter in der Ausführung. Wenn ich keine WinControls verwende macht es eigentlich keinen sinn darauf abzuleiten genauso wenig wie auf TComponent. Es stört mich nicht weiter da es funktioniert aber einen sinn ergibt das nicht wirklich. Ich könnte hier einfach tmpAudioVolume.Free mit tmpAudioVolume := Nil ersetzen. Aber es hängt noch mehr davon ab denn in Destroy müssen viele Dinge freigegeben werden. Deshalb wäre das keine Lösung. gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
Delphi-Quellcode:
als Objektreferenz gehalten werden, nicht als Interface. Erzeugen im Constructor und Freigeben im Destructor.
TAudioVolume
Delphi-Quellcode:
selbst implementiert dann gar kein Interface mehr und braucht auch nicht von
TAudioVolume
Delphi-Quellcode:
abzuleiten, sondern nur vom guten alten
TInterfacedObject/TInterfacedPersistent
Delphi-Quellcode:
.
TObject
Was intern mit dem Proxy passiert ist dadurch streng reguliert (da die Proxy Instanz privat ist, nie als Interface angesprochen wird und Erzeugung und Freigabe von
Delphi-Quellcode:
geregelt wird.
TAudioVolume
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
funktioniert leider nicht und ich musste einiges umbauen.
FProxy.Free; invalid Pointer Ich lasse es jetzt wie es ist. gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
Delphi-Quellcode:
Aufrufe generiert ... aber das sollte dann ja eigentlich nicht am Interface bzw.
AddRef
Delphi-Quellcode:
selbst liegen, sondern ein Programmierfehler sein, oder liege ich hier falsch?
TInterfacedObject
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Hast du dir schon mal überlegt, warum dieser Proxy-Typ
Delphi-Quellcode:
diese Interfacs in der Deklaration aufweist?
TAudioVolumeProxy = class( TInterfacedObject,
IAudioVolume, IAudioSessionEvents, IMMNotificationClient, IAudioSessionNotification, IAudioEndpointVolumeCallback) Evtl. weil die verwendet werden um sich z.B. an einem
Delphi-Quellcode:
per
IAudioSessionControl
Delphi-Quellcode:
anzumelden, weil diese Interfaces ansonsten nutzlos wären wenn man die gar nicht verwendet?
HRESULT RegisterAudioSessionNotification( [in] IAudioSessionEvents *NewNotifications );
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Sehe ich kein Problem, sofern man ordnungsgemäß auch wieder
Delphi-Quellcode:
verwendet. Ich meine "irgendwo" müssen die Referenzen doch geleaked werden. Die entstehen ja nicht von alleine. Dann einfach die Referenzzählung zu deaktivieren, indem man
UnregisterAudioSessionNotification
Delphi-Quellcode:
verwendet, kann doch eigentlich nicht Sinn der Sache sein.
TInterfacedPersistence
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Wenn du dir selber aber die Interface Referenz nicht merkst
(dein Beispiel-Code)
Delphi-Quellcode:
und du gibst eine Interface-Referenz davon heraus, dann tickt ab da die RefCount-Bombe und die kann zu jedem Zeitpunkt platzen.
TAudioVolume = class(TObject)
strict private FProxy: TAudioVolumeProxy; strict protected FOnSessionCreate: TOnSessionCreate; public property OnSessionCreate: TOnSessionCreate read FOnSessionCreate write FOnSessionCreate; ...
Delphi-Quellcode:
begin
RegisterAudioSessionNotification(FProxy); UnregisterAudioSessionNotification(FProxy); end; { bumm, wenn diese Methode verlassen wird, denn wird FProxy zerstört } |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Delphi-Quellcode:
Genau so habe ich es umgesetzt also self mit FProxy ersetzt.
begin
RegisterAudioSessionNotification(FProxy); UnregisterAudioSessionNotification(FProxy); end; { bumm, wenn diese Methode verlassen wird, denn wird FProxy zerstört } Dann die ganzen OnEvents.. nach TAudioVolumeProxy portiert. Da die ganzen Events strict private sind konnte ich von außen die Events nicht mehr zuweisen. Danach habe ich es dann gelassen ;) Alle zugriffe in den Funktionen OnEvents habe ich dann mit FOwner angesprochen. gruss |
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Zitat:
Generell sollte es aber doch trotzdem möglich sein (wenn man sich dann eben 1 Interface-Referenz merkt), ein Leaken zu vermeiden, wenn man entsprechende
Delphi-Quellcode:
und
AddRef
Delphi-Quellcode:
Aufrufe immer ausschließlich in Paaren ausführt. Ich vermute, dass hier einfach irgendwo ein paar versteckte
Release
Delphi-Quellcode:
Aufrufe stattfinden (z.B. innerhalb eines API Calls) zu denen es kein
AddRef
Delphi-Quellcode:
gibt.
Release
Zitat:
Delphi-Quellcode:
kannst du auch weglassen, aber muss zugeben, dass ich die Komponente auch nicht in ihrer Gesamtheit angeschaut habe, weshalb ich nicht weiß, ob es den Aufwand wert ist.
strict
Was du allerdings mal machen könntest, ist
Delphi-Quellcode:
und
AddRef
Delphi-Quellcode:
zu überschreiben und Breakpoints zu setzen. Dann kannst du vielleicht nachvollziehen, wo es zu Aufrufen von
Release
Delphi-Quellcode:
kommt, ohne dass danach
AddRef
Delphi-Quellcode:
aufgerufen wird.
Release
|
AW: TWinControl via TInterfacedObject via TInterfacedPersistent
Hier mal ein Beispiel, wie so etwas gehen kann
Delphi-Quellcode:
und ein kleiner Test dazu
type
IFoo = interface ['{a895c8b4-db8c-40e9-a907-a0a4b01ff773}'] procedure Bar; end; TFooImplementer = class(TObject,IFoo) private type IFooProxy = interface(IFoo) ['{20920822-173c-4e67-8f7b-8959366cc6b2}'] procedure Release; end; strict private FProxy: IFooProxy; function GetFoo: IFoo; strict protected property Foo: IFoo read GetFoo implements IFoo; public constructor Create; destructor Destroy; override; procedure Bar; // Die Methode macht die echte Arbeit end; TInterfacedFooProxy = class(TInterfacedObject, IFoo, TFooImplementer.IFooProxy) strict private FFoo: TFooImplementer; strict protected procedure Bar; strict protected procedure Release; public constructor Create(AFoo: TFooImplementer ); destructor Destroy; override; end; { TFooImplementer } procedure TFooImplementer.Bar; begin WriteLn('*** TFooImplementer.Bar ***'); end; constructor TFooImplementer.Create; begin inherited Create; FProxy := TInterfacedFooProxy.Create(Self); end; destructor TFooImplementer.Destroy; begin WriteLn('TFooImplementer.Destroy'); FProxy.Release; inherited; end; function TFooImplementer.GetFoo: IFoo; begin Result := FProxy; end; { TInterfacedFooProxy } procedure TInterfacedFooProxy.Bar; begin WriteLn('TInterfacedFooProxy.Bar'); if Assigned(FFoo) then FFoo.Bar; end; constructor TInterfacedFooProxy.Create(AFoo: TFooImplementer); begin inherited Create; FFoo := AFoo; end; destructor TInterfacedFooProxy.Destroy; begin WriteLn('TInterfacedFooProxy.Destroy'); inherited; end; procedure TInterfacedFooProxy.Release; begin FFoo := nil; end;
Delphi-Quellcode:
und was dabei herauskommt
procedure Main;
var fooObj : TFooImplementer; fooIntf: IFoo; begin fooObj := TFooImplementer.Create; try fooIntf := fooObj; // direkter Aufruf fooObj.Bar; // indirekter Aufruf durch IFoo fooIntf.Bar; finally fooObj.Free; fooObj := nil; end; // indirekter Aufruf durch IFoo, der aber ins Leere geht fooIntf.Bar; fooIntf := nil; end;
Code:
*** TFooImplementer.Bar ***
TInterfacedFooProxy.Bar *** TFooImplementer.Bar *** TFooImplementer.Destroy TInterfacedFooProxy.Bar TInterfacedFooProxy.Destroy |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:39 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz