Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Object (Interface) <> nil (https://www.delphipraxis.net/193802-object-interface-nil.html)

EWeiss 11. Sep 2017 12:34


Object (Interface) <> nil
 
Ich erstelle ein Interface.

Delphi-Quellcode:
  PopUpMenu := CTRL_PopUpMenuCreate;


Wenn ich nun ein Item des PopUpMenu klicke beende ich das Interface bsp. TSkinPopUpMenu mit Free. (In der DLL)

Das Object ist nun NIL nur wie soll ich das der Anwendung mitteilen? Ohne extra Funktionen dafür erstellen zu müssen. (soll Automatisiert ablaufen)
Ein Prüfen auf
Delphi-Quellcode:
if not Assigned(PopUpMenu) then


würde in dem Fall nichts bringen.
Wieder so ein Spezial fall.

Das ist die Fehlermeldung die ich bekomme wenn PopUpMenu in der DLL NIL ist aber nicht in der Anwendung.
Ich könnte das Object selbst auf NIL setzen
Delphi-Quellcode:
    IDM_About:
      begin
        PopUpMenu := nil;
Nur das ist nicht der sinn der Sache.

gruss

himitsu 11. Sep 2017 13:13

AW: Object (Interface) <> nil
 
Das Menü oder mindestens das Interface, für den Zugriff darauf, gibt sich nicht frei, sondern erst wenn es keine Referenz mehr gibt ... Interface halt :zwinker:

EWeiss 11. Sep 2017 13:24

AW: Object (Interface) <> nil
 
Zitat:

Zitat von himitsu (Beitrag 1380776)
Das Menü oder mindestens das Interface, für den Zugriff darauf, gibt sich nicht frei, sondern erst wenn es keine Referenz mehr gibt ... Interface halt :zwinker:

Meine Classe aber oder?
Delphi-Quellcode:
  TSkinPopUpMenu = class(TInterfacedPersistent, ISkinPopUpMenu)


gruss

mkinzler 11. Sep 2017 13:44

AW: Object (Interface) <> nil
 
Dzu gibtst die nstanz der Klasse frei, diese verringert den Referenzzähler des Interfaces. Ist dieser dann 0 wird dieses auch Freigeben.

EWeiss 11. Sep 2017 13:51

AW: Object (Interface) <> nil
 
Zitat:

Zitat von mkinzler (Beitrag 1380785)
Dzu gibtst die nstanz der Klasse frei, diese verringert den Referenzzähler des Interfaces. Ist dieser dann 0 wird dieses auch Freigeben.

Die Classe TSkinPopUpMenu ist frei.
Nur die Anwendung bekommt ja nichts davon mit das ist mein Problem.

Und selbst setze ich sie nicht auf NIL in der DLL das geschieht automatisch sobald wie du sagst alle Referenzzähler auf 0 sind.

gruss

sakura 11. Sep 2017 14:04

AW: Object (Interface) <> nil
 
Zitat:

Zitat von EWeiss (Beitrag 1380787)
Nur die Anwendung bekommt ja nichts davon mit das ist mein Problem.

Solange Du in der Anwendung eine Variable hast, welche auf das Interface des Objektes zeigt, wird dieses nicht automatisch freigegeben.

Wenn Du also willst, dass das Objekt, zu welchem das Interface gehört, freigegeben wird, musst Du zuvor auch in der Anwendung die Variable auf nil setzen.

...:cat:...

sakura 11. Sep 2017 14:05

AW: Object (Interface) <> nil
 
Des Weiteren werden Variablen nicht irgendwie durch "Magie" auf nil gesetzt, sobald ein Objekt zerstört wird. Dazu müsste das Programm jederzeit jede Kopie - egal wie diese erstellt wurde - des Pointers kennen. Und das ist so nicht möglich.

...:cat:...

jaenicke 11. Sep 2017 14:10

AW: Object (Interface) <> nil
 
Zitat:

Zitat von EWeiss (Beitrag 1380769)
Wenn ich nun ein Item des PopUpMenu klicke beende ich das Interface bsp. TSkinPopUpMenu mit Free. (In der DLL)

Zwei Grundregeln musst du bei der Arbeit mit Interfaces beachten:
  • Niemals eine Referenz auf das Objekt behalten und nutzen! Immer nur mit dem Interface arbeiten. Schon gar nicht das Objekt mit Free freigeben und damit allen Interfaces unter dem Allerwertesten wegziehen. Das gibt sehr schöne Fehler...
  • Vor der Freigabe der DLL müssen alle Interfacereferenzen auf Interfaces der DLL im Hauptprogramm auf nil gesetzt werden und umgekehrt. Dafür sollte die DLL-Schnittstelle sinnvollerweise entsprechende Mechanismen anbieten.
Hintergrund ist, dass beim Setzen des Interfaces auf nil immer dessen Methode Release aufgerufen wird. Ist das Objekt dahinter dann schon freigegeben, knallt es logischerweise.

EWeiss 11. Sep 2017 14:16

AW: Object (Interface) <> nil
 
Zitat:

musst Du zuvor auch in der Anwendung die Variable auf nil setzen.
warum zuvor und nicht nachher?

Ok ich versuche es mal auf dem weg
Delphi-Quellcode:
    WM_NCRBUTTONDOWN:
      begin
        if Assigned(PopUpMenu) then
          PopUpMenu := Nil;
        CreatePopupMenu(WinHandle);

        GetCursorPos(p);
        GetWindowRect(gPMenu.PopUpMenu, rc);
        ClientToScreen(gPMenu.PopUpMenu, p);

        MenuWahl := PopUpMenu.TrackPopupMenu(gPMenu.PopUpMenu, p.x, (p.y - rc.Bottom), rc.Right,
          rc.Bottom);

        if MenuWahl then
          SendMessage(WinHandle, WM_COMMAND, Makelong(word(MenuWahl), 0), 0);
      end;
Irgendwie widerspricht das jeglicher Logik.
Denn die Anwendung weis nicht ob das Object in der DLL frei ist oder nicht.

gruss

sakura 11. Sep 2017 14:19

AW: Object (Interface) <> nil
 
Zitat:

Zitat von EWeiss (Beitrag 1380794)
Denn die Anwendung weis nicht ob das Object in der DLL frei ist oder nicht.

Wie sollte es die Anwendung den wissen, wenn diese nicht informiert wird? :gruebel:

...:cat:...

EWeiss 11. Sep 2017 14:24

AW: Object (Interface) <> nil
 
Zitat:

Zitat von sakura (Beitrag 1380795)
Zitat:

Zitat von EWeiss (Beitrag 1380794)
Denn die Anwendung weis nicht ob das Object in der DLL frei ist oder nicht.

Wie sollte es die Anwendung den wissen, wenn diese nicht informiert wird? :gruebel:

...:cat:...

Macht das ein normales Menu auch?
Ich möchte unnötige Funktionen vermeiden wenn das möglich ist.

Hmm...

Vielleicht bin ich auch im Moment etwas überfordert.
Ärgere mich schon lange damit rum.

Zitat:

•Niemals eine Referenz auf das Objekt behalten und nutzen! Immer nur mit dem Interface arbeiten. Schon gar nicht das Objekt mit Free freigeben und damit allen Interfaces unter dem Allerwertesten wegziehen. Das gibt sehr schöne Fehler...
Habe es behoben vorher habe ich in Destroy Free verwendet jetzt beende ich meine Windows ohne Free.
und das Object ist trotzdem NIL.

OK muss mal sehen wie ich das hinbiege.

gruss

stahli 11. Sep 2017 14:54

AW: Object (Interface) <> nil
 
Ich habe jetzt Dein Problem und den Hintergrund der Frage nicht eindeutig verstanden.

Wenn Du von TInterfacedPersistent ableitest, gibt es jedenfalls keine Referenzählung und keine automatische Freigabe des Objektes.

Wenn Du eine Referenzzählung benutzt, also z.B.

Var1 := O;
Var2 := O;
Var3 := O;

dann wird das Objekt O freigegeben, wenn allen 3 Variablen Nil (oder ein anderes Objekt) zugewiesen wurde und keine weitere Referenz auf O existiert.

Wenn Du statt dessen O.Free aufrufst, hast Du hängende Pointer auf ein freigegebenes Objekt. Das sollte man natürlich vermeiden.


Offenbar brauchst Du die Verwendung als Interface in einer DLL.
Dann kannst Du entweder automatische Referenzzählung und -Freigabe verwenden und solltest aber sämtliche Zugriffe auf das Objekt auch über ein Interface regeln oder Du verzichtest auf die Referenzzählung und regelst die Lebenszeit des Objektes und die Zuweisung aller entsprechenden Variablen selbst.

Ggf. könnte man globale Methoden einrichten, die das abwickeln.
procedure CreateMyObject;
procedure DestroyMyObject;
Je nach Zielstellung und Umständen gibt es da sicher verschiedene Möglichkeiten.

Neutral General 11. Sep 2017 15:02

AW: Object (Interface) <> nil
 
Ich muss gestehen dass ich den Thread nur überflogen habe aber kann es sein dass die Lösung des Problems wäre dass dein Programm und die DLL einfach die einfach Regel befolgen: "Wer es erstellt, der gibt es auch frei"?

Wenn die DLL ein PopupMenu(Item) erstellt, dann geht die Anwendung davon aus dass dieses Item existiert und zwar solange bis die DLL der Anwendung mitteilt, dass das Item freigegeben werden soll. Die Anwendung muss der DLL vertrauen und umgekehrt und niemand darf dem anderen reinpfuschen. Das ist schon die halbe Miete.

EWeiss 11. Sep 2017 15:06

AW: Object (Interface) <> nil
 
Ich erstelle ein Menu basierend auf Interface.

In der Anwendung..

Delphi-Quellcode:
  PopUpMenu := CTRL_PopUpMenuCreate;


Delphi-Quellcode:
function CTRL_PopUpMenuCreate(): ISkinPopUpMenu; stdcall; external dllfile;

usw..

Ich möchte nichts anderes als meiner Anwendung mitteilen das dass erstellte Object Nil ist.
Und nicht Quasi aus einer Laune heraus das erstelle Interface in der Anwendung selbst auf Nil setzen.
Zitat:

"Wer es erstellt, der gibt es auch frei"?
richtig nur ein Standard Menu macht das nicht oder?
Es liefert keine Funktion zurück welche da sagt hallo bin fertig du kannst mich platt machen. ;)


gruss

Neutral General 11. Sep 2017 15:13

AW: Object (Interface) <> nil
 
Warum ist das Objekt denn nil?
Wenn es erst gar nicht erstellt werden konnte kannst du ja mit CTRL_PopUpMenuCreate einfach "nil" zurückgeben.
Falls das Erstellen aber geklappt hat, dann gibt es keinen Grund warum du als DLL der Anwendung mitteilen müsstest dass das PopupMenu nil ist.
Denn entweder hat die Anwendung das selbst angeordnet oder die DLL hat sich eingemischt und das Popup der Anwendung freigegeben was genau dem widerspricht was ich oben gesagt hab.

Die Anwendung hat CTRL_PopUpMenuCreate aufgerufen also bleibt das erstelle PopupMenu solange erhalten bis die Anwendung es zerstört.

Alternativ kannst du vllt bei CTRL_PopUpMenuCreate als Parameter ein Callback übergeben lassen was die Anwendung informiert wenn das erstellte PopupMenu zerstört wurde.
Das wäre noch eine akzeptable Alternative denk ich.

EWeiss 11. Sep 2017 15:31

AW: Object (Interface) <> nil
 
Zitat:

Warum ist das Objekt denn nil?
Hat niemand etwas von gesagt das es Nil ist ;)

Delphi-Quellcode:
function CTRL_PopUpMenuCreate(): ISkinPopUpMenu; stdcall;
begin

  result := TSkinPopUpMenu.Create();
end;
das schlägt niemals fehl.
Mit CTRL_PopUpMenuCreate wird nur das Interface erstellt.

Was fehl schlagen könnte ist wenn das Window nicht erstellt wird.
Nach dem alle benötigten Funktionen gefüllt wurden wird das Window erstellt.
Delphi-Quellcode:
  gPMenu.hPopUpHandle := PopUpMenu.CreatePopupMenu(WinHandle);
  if gPMenu.hPopUpHandle <> 0 then
  begin
und liefert ein HWND zurück.

Das ist aber nicht mein Problem sondern ich sage es nochmal PopUpMenu auf Nil zu setzen wenn in der DLL TSkinPopUpMenu ebenfalls Nil ist.
Und das ganze wenn möglich ohne zusätzliche Funktionen da ich versuche das verhalten des originalen Menus zu emulieren.

Scheint so das mich keiner versteht. :)

gruss

TiGü 11. Sep 2017 15:38

AW: Object (Interface) <> nil
 
Zitat:

Zitat von EWeiss (Beitrag 1380808)
Das ist aber nicht mein Problem sondern ich sage es nochmal PopUpMenu auf Nil zu setzen wenn in der DLL TSkinPopUpMenu ebenfalls Nil ist.
Und das ganze wenn möglich ohne zusätzliche Funktionen da ich versuche das verhalten des originalen Menus zu emulieren.

Scheint so das mich keiner versteht. :)

Du bist eben auch kein Erklärbär.

Speicherst du dir irgendwo (in einer globalen Variablen) das Objekt mit dem Typ TSkinPopUpMenu in der DLL ab?
Und auf dieses rufst du dann TSkinPopUpMenu.Free auf?

EWeiss 11. Sep 2017 15:46

AW: Object (Interface) <> nil
 
Zitat:

Und auf dieses rufst du dann TSkinPopUpMenu.Free auf?
Nein ich rufe überhaupt kein Free auf. (Habe es geändert da man das nicht tun soll)

Das Interface ist dann frei wenn alle Referenzen auf 0 sind.
Also ich beende alle Ressourcen und zerstöre alle Objecte (Windows usw..) die vom Interface verwendet werden.
Danach ist dieses automatisch frei..

gruss

TiGü 11. Sep 2017 15:50

AW: Object (Interface) <> nil
 
Zitat:

Zitat von EWeiss (Beitrag 1380811)
Zitat:

Und auf dieses rufst du dann TSkinPopUpMenu.Free auf?
Nein ich rufe überhaupt kein Free auf. (Habe es geändert da man das nicht tun soll)

Das Interface ist dann frei wenn alle Referenzen auf 0 sind.
Also ich beende alle Ressourcen und zerstöre alle Objecte (Windows usw..) die vom Interface verwendet werden.
Danach ist dieses automatisch frei..

Dein Problem ist also damit gelöst?

Neutral General 11. Sep 2017 15:55

AW: Object (Interface) <> nil
 
Zitat:

Zitat von EWeiss (Beitrag 1380811)
Das Interface ist dann frei wenn alle Referenzen auf 0 sind.
Also ich beende alle Ressourcen und zerstöre alle Objecte (Windows usw..) die vom Interface verwendet werden.
Danach ist dieses automatisch frei..

Ist das nicht trotzdem genau das Problem von dem ich die ganze Zeit rede?
Die DLL macht das von der Anwendung angeforderte Objekt selbstständig und ohne dass die Anwendung es angefordert hat komplett unbrauchbar bzw. gibt alles frei.
Genau das soll die DLL nicht machen. Entweder du gibst das Objekt/die vom Objekt benutzen Resource erst frei wenn die Anwendung das von sich aus anfordert oder du teilst der Anwendung per Callback (wie weiter oben von mir vorgeschlagen) mit dass das Popupmenu was es eben erstellt hat jetzt kaputt ist.

stahli 11. Sep 2017 15:56

AW: Object (Interface) <> nil
 
Zitat:

Zitat von EWeiss (Beitrag 1380805)
Ich möchte nichts anderes als meiner Anwendung mitteilen das dass erstellte Object Nil ist.

Um hier helfen zu können, müsste erst mal klar sein, wer das erstelle Objekt auf Nil setzt.
Das ist letztlich schon die falsche Beschreibung. Ein Objekt kann nicht auf Nil gesetzt werden. Dieses kann man höchstens freigeben (also dessen Speicherbereich wiederverwendbar machen).
Eine Variable kann man auf Nil setzen.

Willst Du also erkennen, ob das Objekt freigegeben wurde oder ob eine Variable auf Nil gesetzt wurde?

Eine diesbezügliche Interaktion zwischen DLL und Anwendung wird wohl in beiden Fällen nicht gehen (es sei denn, es würde ein Interface-Property als Informationsstelle benutzt).

Wenn die DLL außen vor bleiben kann und nur die Anwendung über die Objekt-Existenz informiert sein muss, gibt es mehrere (ziemlich triviale) Möglichkeiten.


Wenn Du die "Existenz Deines Objektes" nur in der Anwendung abfragen musst, die auch die Klasse (nicht nur das Interface kennt), und immer nur eine Instanz davon existieren kann, könntest Du eine Klassenvariable
Delphi-Quellcode:
PopupMenuExist: Boolean;
einrichten und diese im Constructor auf True und im Destructor auf False setzen.
Dann könntest Du abfragen, ob eine gütige Instanz existiert oder nicht.

Das setzt aber nicht Deine Variable auf Nil.
Dazu könntest Du evtl. eine globale Variable verwenden, die im Constuctor auf Self und im Destructor auf Nil gesetzt wird.

Oder Du folgst dem General und regelst die Rückinfo über ein Callback.


[EDIT]
Zusammenfassend die Frage: Wird aktuell der Destructor Deiner TPopupMenu-Klasse korrekt aufgerufen (egal unter welchen genauen Umständen)? Dann halte dort den Status für die Anwendung fest. Bestenfalls in einer globalen Variable gMyPopupMenu := Nil und im Contructor gMyPopupMenu := Self.
Dann kannst Du jederzeit auf Assigned(gMyPopupMenu) prüfen...
Das geht problemlos, wenn immer nur eine Instanz dieser Klasse leben kann.

EWeiss 11. Sep 2017 16:41

AW: Object (Interface) <> nil
 
Zu 1.
Es gibt keinen Destructor da hier jemand gesagt hat das ich das Interface nicht selbst auf NIL setzen kann.
Daher benötige ich den nicht.

Zu 2.
Ja im Contructor wird die Variable SkinPopUpMenu := self; zugewiesen.

Zitat:

Dann kannst Du jederzeit auf Assigned(gMyPopupMenu) prüfen...
Und genau das mache ich in der DLL um zu prüfen ob das Object (Interface wie auch immer) frei ist.

Damit habe ich aber der Anwendung immer noch nicht mitgeteilt das mein Object Nil ist.

Danke für eure Hilfe werde das wohl selbst regeln müssen.
Ohne Vollständigen Code nutzt euch das nichts da ihr nicht sehen könnt was abgeht.

gruss

Neutral General 11. Sep 2017 16:50

AW: Object (Interface) <> nil
 
Anwendung:
Delphi-Quellcode:
var popup: ISkinPopUpMenu;
begin
  popup := CTRL_PopUpMenuCreate(OnPopupDestroyed);
end;

procedure OnPopupDestroyed()
begin
  ShowMessage('Popup wurde in der DLL auf nil gesetzt!');
end;
DLL:
Delphi-Quellcode:
var
  CallbackZurAnwendung: TCallback;

function CTRL_PopUpMenuCreate(callback: TCallback): ISkinPopUpMenu; stdcall;
begin
  result := TSkinPopUpMenu.Create();
  CallbackZurAnwendung := callback;
end;

// ...
// Wenn das Popupmenu auf nil gesetzt wird:
CallbackZurAnwendung(PopupMenu);
PopupMenu := nil;

EWeiss 11. Sep 2017 16:56

AW: Object (Interface) <> nil
 
Danke werde es mal testen
Wenn dann ist das wohl die beste Lösung ohne zusätzliche Funktionen.

gruss

stahli 11. Sep 2017 17:28

AW: Object (Interface) <> nil
 
In jedem Fall würde ich den Destructor an Deiner Stelle überschreiben.
Du musst ja darin neben dem inherited nichts tun und Du musst ja Free auch nicht aufrufen, aber so kannst Du bei Bedarf mal einen Haltepunkt setzen und sehen, ob und wann Dein Objekt wirklich freigegeben wird (einfach nur zur Ablaufkontrolle).

Und Du solltest m.E. auch nicht davon sprechen, ob ein Objekt oder Interface = Nil ist, sondern ob eine Variable Nil ist.
Das ist auch zum eigenen Verständnis bei solchen Problemen wichtig, da es ja mehrere Variablen geben kann, die ein Objekt referenzieren.
Auch ändert die Objektfreigabe nichts an diesen Variablen. Lediglich Zugriffe auf diese können später unvorhersehbare Probleme bis hin zum Programmabsturz verursachen.

EWeiss 11. Sep 2017 17:54

AW: Object (Interface) <> nil
 
Zitat:

In jedem Fall würde ich den Destructor an Deiner Stelle überschreiben.
Du musst ja darin neben dem inherited nichts tun und Du musst ja Free auch nicht aufrufen, aber so kannst Du bei Bedarf mal einen Haltepunkt setzen und sehen, ob und wann Dein Objekt wirklich freigegeben wird (einfach nur zur Ablaufkontrolle).
leere funktion die nichts tut ?
Wenn du meinst das ist besser werde ich es addieren.

Zitat:

Und Du solltest m.E. auch nicht davon sprechen, ob ein Objekt oder Interface = Nil ist, sondern ob eine Variable Nil ist.
Verstehe ich nicht ganz einzelne Variablen ? Wenn doch das Interface aus mehreren besteht.

gruss

stahli 11. Sep 2017 18:31

AW: Object (Interface) <> nil
 
Im Destructor muss man natürlich inherited aufrufen.
Ich finde das übersichtlicher, diesen auch zu überschreiben wenn man Konstruktoren definiert (ist aber nur Gewohnheitssache).
Aber Du kannst halt einen Haltepunkt setzten und sehen, ob das Objekt überhaupt freigegeben wird und wann.


Zu den Objekten und Interfaces, schau mal, ob Dir das zum Verständnis hilft: http://www.delphipraxis.net/1288384-post13.html

Wenn Du auf ein Interface zugreifst, ist das letztlich der Zugriff auf ein Teilstück eines Objektes. Das ist also ein etwas eingeschränkter Zugriff auf die Daten und Methoden des Objektes.

Das hat aber mit Variablen direkt nichts zu tun.

Was ich sagen wollte ist, dass eine Freigabe eines Objektes keine Variable auf Nil setzt und eine Zuweisung von Nil an eine Variable kein Objekt (bzw. keinen Speicherplatz) freigibt. (Die einzige Ausnahme ist bei Verwendung der automatischen Referenzzählung und Zuweisung von Nil an die letzte referenzierende Variable. Die Referenzzählung bezieht sich dabei immer auf das Objekt hinter den Interfaces - also bei zwei Referenzen auf Interface A und 2 auf Interface B eines Objektes erhöht die Referenzzählung des Objektes auf 4. Es gibt nicht je zwei Referenzzählerwerte auf Interface A und B.)

Die Trennung von Objektfreigabe und Variablenreferenz = NIL muss man gerade bei so einer Problemlösungssuche trennen, weil man sich sonst sprachlich einfach nicht verstehen kann.
Delphi-Quellcode:
MyIntf := Nil;
kann zu einer Auflösung des Objektes führen oder auch nicht.
Auf eines von beiden zu reagieren sind zwei verschiedene Paar Schuhe.

EWeiss 11. Sep 2017 18:40

AW: Object (Interface) <> nil
 
Danke dir für die Infos..

gruss

EWeiss 11. Sep 2017 20:02

AW: Object (Interface) <> nil
 
Ich habe es jetzt so gemacht.

Anwendung:
Delphi-Quellcode:
type
  TPopUpState = (OnPopupDestroyed);
  POPUPSTATECALLBACK = procedure(PopUpState: TPopUpState); stdcall;
Delphi-Quellcode:
  PopUpMenu := CTRL_PopUpMenuCreate(PopUpCallback);
Delphi-Quellcode:
procedure PopUpCallback(PopUpState: TPopUpState); stdcall;
begin
  case PopUpState of
    OnPopupDestroyed:
      PopUpMenu := nil;
  end;
end;
DLL:
Delphi-Quellcode:
var
  PopUpCallback : POPUPSTATECALLBACK;
Delphi-Quellcode:
function CTRL_PopUpMenuCreate(callback: POPUPSTATECALLBACK): ISkinPopUpMenu; stdcall;
begin

  result := TSkinPopUpMenu.Create();
  PopUpCallback := callback;
end;
Wenn Nil..
Delphi-Quellcode:
if SkinPopUpMenu = nil then
  PopUpCallback(OnPopupDestroyed);
funktioniert ganz gut kann es so belassen.
Danke für die Hilfe.

gruss

stahli 11. Sep 2017 20:17

AW: Object (Interface) <> nil
 
Ok, fein.
Wenn es so klappt, ist es schön.
Ich will auch nicht nochmal zur Verwirrung beitragen, aber vielleicht kannst Du mal noch nach zwei Dingen schauen:

Hast Du Deine Klasse von TInterfacedPersistent abgeleitet oder von TInterfacedObject?
Wird Dein Destructor des Objektes irgendwann aufgerufen?

Ich vermute, dass Dein Objekt aktuell nicht freigegeben wird. Das wäre nicht unbedingt ein Drama, aber erzeugt dann halt ein Speicherleck.

Wenn Du Dich darum noch kümmern willst, könnte man dem noch nachgehen...

EWeiss 11. Sep 2017 20:22

AW: Object (Interface) <> nil
 
Zitat:

Hast Du Deine Klasse von TInterfacedPersistent abgeleitet oder von TInterfacedObject?
Delphi-Quellcode:
TSkinPopUpMenu = class(TInterfacedPersistent, ISkinPopUpMenu)


Alle von TInterfacedPersistent.

Wird Dein Destructor des Objektes irgendwann aufgerufen?
Delphi-Quellcode:
destructor TSkinPopUpMenu.Destroy;
begin

  inherited;
end;
Nein niemals weil ich kein Free verwende.
Aber ich habe ihn addiert.

gruss

stahli 11. Sep 2017 20:25

AW: Object (Interface) <> nil
 
Ok, dann nur mal als Hinweis, falls Du das mal noch versuchen willst:

Du könntest von TInterfacedObject ableiten.
Dann wird das Objekt freigegeben, wenn die letzte Referenz darauf wegfällt.

Oder Du könntest es so lassen und selbst Free aufrufen.

Beides würde halt ein Speicherleck vermeiden.

EWeiss 11. Sep 2017 20:32

AW: Object (Interface) <> nil
 
Zitat:

Oder Du könntest es so lassen und selbst Free aufrufen.
Verstehe ich jetzt wirklich nicht.

http://www.delphipraxis.net/1380793-post8.html
Schon gar nicht das Objekt mit Free freigeben

sorry aber was ist denn nun richtig!
Habe jetzt alles geändert so das kein Free mehr aufgerufen wird.

ändere ich es nach TInterfacedObject dann wird Destroy aufgerufen ohne Free zu bemühen.

gruss

stahli 11. Sep 2017 21:17

AW: Object (Interface) <> nil
 
Du darfst das Objekt nicht freigeben, solange noch darauf oder auf seine Schnittstellen zugegriffen werden kann.

Also Du hast z.B.
Delphi-Quellcode:
myObj := TMyObj.Create;
myIntf1 := myObj;
myIntf2 := myObj;
Wenn Du TMyObj von TInterfacedObj ableitest, wird die automatische Referenzzählung unterstützt.
Wenn Du jetzt
Delphi-Quellcode:
myObj := nil;
myIntf1 := nil;
myIntf2 := nil;
aufrufst, wird automatisch TMyObj.Destroy aufgerufen.
Dazu ggf. der Haltepunkt dort, um das nachzuverfolgen.
Sofern Du aber irgendwo noch eine Referenz auf das Objekt hältst, ist der Referenzzähler noch größer 0 und das Objekt bleibt noch bestehen.

Bei diesem Schnipsel fällt auf, dass
Delphi-Quellcode:
myObj := nil
irgendwie aus dem Rahmen fällt. Diese Variable bezieht sich auf das Objekt selbst (hält also eine Klasseninstanz). Wenn man die auf Nil setzt, hat das keine Auswirkung auf das Objekt selbst.

Wenn man myObj.Free aufruft bevor myIntf1 und myIntf2 auf nil gesetzt sind, wird das Objekt freigegeben (quasi gelöscht) und bei einem Zugriff auf myIntf1 oder myIntf2 kann/wird es knallen.

Eigentlich ist die Klassenvariable also hier fehl am Platz und man würde das eher so schreiben:
Delphi-Quellcode:
myIntf1 := TMyObj.Create;
myIntf2 := myIntf1;
..
myIntf1 := nil;
myIntf2 := nil;
Hier arbeitet man nur noch mit den Interfaces und es ist egal, was da für eine Klasse instanziiert wurde.
Wenn alle Referenzen wegfallen, wird das Objekt freigegeben.


Wenn Du aber von TInterfacedPersistend ableitest, gibt es keine Referenzzählung und keine automatische Freigabe des Objektes.
Daher musst Du (um ein Speicherleck zu vermeiden) das Objekt wieder selbst freigeben - i.d.R. auf der Ebene, wo es erzeugt wurde.
Dann kümmerst Du Dich ganz normal selbst um die Lebenszeit der Objekte und nutzt die Interfaces nur zur Vereinheitlichung der Klassenstrukturen.

So müssen nicht Klassen zueinander passen, sondern nur Klassenteile.

EWeiss 11. Sep 2017 21:24

AW: Object (Interface) <> nil
 
So weit habe ich das verstanden.
Verwende jetzt TInterfacedObj Mein Interface ist Nil und Destroy wird automatisch aufgerufen.

Dann sollte das so stimmen. ;)
Danke dir.

gruss

stahli 11. Sep 2017 21:40

AW: Object (Interface) <> nil
 
:thumb:

Jetzt könntest Du ggf. noch ohne den Callback auskommen.
Du bekommst ja jetzt im destructor mit, dass das Objekt freigegeben wird.
Jetzt könntest Du auch dort
Delphi-Quellcode:
PopUpMenu := nil;
ausführen.

Ist aber Geschmacksache und würde sofort nicht mehr funktionieren, wenn durch Änderungen am Projekt irgendwann doch noch irgendwo eine Referenz auf das Objekt hängen würde.

EWeiss 11. Sep 2017 21:54

AW: Object (Interface) <> nil
 
Zitat:

Jetzt könntest Du auch dort PopUpMenu := nil; ausführen.
Nein kann ich nicht weil PopUpMenu := Nil ohne Callback in der Hauptanwendung nicht ankommt.
In der DLL nutzt es auch nichts denn PopUpMenu ist eine Variable in den Main App

Davon ab habe noch genug andere Problem mit den Events trotz SubClasses will nicht so recht.
Irgendwas ist immer... schwierig ein Menu zu emulieren. Na ja hab ja sonst nix zu tun :)

sind jetzt schon 1600 zeilen.

gruss

stahli 11. Sep 2017 21:59

AW: Object (Interface) <> nil
 
Ok, Hauptsache es funktioniert. :thumb:

EWeiss 11. Sep 2017 22:02

AW: Object (Interface) <> nil
 
Zitat:

Zitat von stahli (Beitrag 1380852)
Ok, Hauptsache es funktioniert. :thumb:

Dito und Danke nochmal.. an alle die mitgeholfen haben.

gruss

EWeiss 13. Sep 2017 18:52

AW: Object (Interface) <> nil
 
Habe doch noch ein Problem

Beim erstellen des Menu wird der FRefCount hochgesetzt also auf 1
Wie kann ich jetzt feststellen warum dieser nicht runtergezählt wird.

Ich bin der Meinung das alles freigegeben wird aber die Referenz schaltet nicht runter finde das Problem nicht.
OK. Denke mal.. hat sich erledigt.

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:58 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz