![]() |
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:
Nur das ist nicht der sinn der Sache.
IDM_About:
begin PopUpMenu := nil; gruss |
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:
|
AW: Object (Interface) <> nil
Zitat:
Delphi-Quellcode:
TSkinPopUpMenu = class(TInterfacedPersistent, ISkinPopUpMenu)
gruss |
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.
|
AW: Object (Interface) <> nil
Zitat:
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 |
AW: Object (Interface) <> nil
Zitat:
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:... |
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:... |
AW: Object (Interface) <> nil
Zitat:
|
AW: Object (Interface) <> nil
Zitat:
Ok ich versuche es mal auf dem weg
Delphi-Quellcode:
Irgendwie widerspricht das jeglicher Logik.
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; Denn die Anwendung weis nicht ob das Object in der DLL frei ist oder nicht. gruss |
AW: Object (Interface) <> nil
Zitat:
...:cat:... |
AW: Object (Interface) <> nil
Zitat:
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:
und das Object ist trotzdem NIL. OK muss mal sehen wie ich das hinbiege. gruss |
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. |
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. |
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:
Es liefert keine Funktion zurück welche da sagt hallo bin fertig du kannst mich platt machen. ;) gruss |
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. |
AW: Object (Interface) <> nil
Zitat:
Delphi-Quellcode:
das schlägt niemals fehl.
function CTRL_PopUpMenuCreate(): ISkinPopUpMenu; stdcall;
begin result := TSkinPopUpMenu.Create(); end; 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:
und liefert ein HWND zurück.
gPMenu.hPopUpHandle := PopUpMenu.CreatePopupMenu(WinHandle);
if gPMenu.hPopUpHandle <> 0 then begin 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 |
AW: Object (Interface) <> nil
Zitat:
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? |
AW: Object (Interface) <> nil
Zitat:
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 |
AW: Object (Interface) <> nil
Zitat:
|
AW: Object (Interface) <> nil
Zitat:
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. |
AW: Object (Interface) <> nil
Zitat:
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:
einrichten und diese im Constructor auf True und im Destructor auf False setzen.
PopupMenuExist: Boolean;
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. |
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:
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 |
AW: Object (Interface) <> nil
Anwendung:
Delphi-Quellcode:
DLL:
var popup: ISkinPopUpMenu;
begin popup := CTRL_PopUpMenuCreate(OnPopupDestroyed); end; procedure OnPopupDestroyed() begin ShowMessage('Popup wurde in der DLL auf nil gesetzt!'); end;
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; |
AW: Object (Interface) <> nil
Danke werde es mal testen
Wenn dann ist das wohl die beste Lösung ohne zusätzliche Funktionen. gruss |
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. |
AW: Object (Interface) <> nil
Zitat:
Wenn du meinst das ist besser werde ich es addieren. Zitat:
gruss |
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: ![]() 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:
kann zu einer Auflösung des Objektes führen oder auch nicht.
MyIntf := Nil;
Auf eines von beiden zu reagieren sind zwei verschiedene Paar Schuhe. |
AW: Object (Interface) <> nil
Danke dir für die Infos..
gruss |
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:
DLL:
procedure PopUpCallback(PopUpState: TPopUpState); stdcall;
begin case PopUpState of OnPopupDestroyed: PopUpMenu := nil; end; end;
Delphi-Quellcode:
var
PopUpCallback : POPUPSTATECALLBACK;
Delphi-Quellcode:
Wenn Nil..
function CTRL_PopUpMenuCreate(callback: POPUPSTATECALLBACK): ISkinPopUpMenu; stdcall;
begin result := TSkinPopUpMenu.Create(); PopUpCallback := callback; end;
Delphi-Quellcode:
funktioniert ganz gut kann es so belassen.
if SkinPopUpMenu = nil then
PopUpCallback(OnPopupDestroyed); Danke für die Hilfe. gruss |
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... |
AW: Object (Interface) <> nil
Zitat:
Delphi-Quellcode:
TSkinPopUpMenu = class(TInterfacedPersistent, ISkinPopUpMenu)
Alle von TInterfacedPersistent. Wird Dein Destructor des Objektes irgendwann aufgerufen?
Delphi-Quellcode:
Nein niemals weil ich kein Free verwende.
destructor TSkinPopUpMenu.Destroy;
begin inherited; end; Aber ich habe ihn addiert. gruss |
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. |
AW: Object (Interface) <> nil
Zitat:
![]() 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 |
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:
Wenn Du TMyObj von TInterfacedObj ableitest, wird die automatische Referenzzählung unterstützt.
myObj := TMyObj.Create;
myIntf1 := myObj; myIntf2 := myObj; Wenn Du jetzt
Delphi-Quellcode:
aufrufst, wird automatisch TMyObj.Destroy aufgerufen.
myObj := nil;
myIntf1 := nil; myIntf2 := nil; 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:
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.
myObj := nil
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:
Hier arbeitet man nur noch mit den Interfaces und es ist egal, was da für eine Klasse instanziiert wurde.
myIntf1 := TMyObj.Create;
myIntf2 := myIntf1; .. myIntf1 := nil; myIntf2 := nil; 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. |
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 |
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:
ausführen.
PopUpMenu := nil;
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. |
AW: Object (Interface) <> nil
Zitat:
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 |
AW: Object (Interface) <> nil
Ok, Hauptsache es funktioniert. :thumb:
|
AW: Object (Interface) <> nil
Zitat:
gruss |
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 14:13 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