Ablauf beim Beenden einer App
-
Hallo!
Beim Debuggen habe ich festgestellt, dass auch nach Verlassen von Application->Run die Anwendung immer noch in der Taskleiste hängt. Wann wird denn das Hauptfenster (bzw. alle Fenster) endgültig geschlossen?
Mit folgendem Konstrukt bekomme ich immer Schutzverletzungen beim Beenden:
TMyClass myclass(); try { Application->Initialize(); Application->Title = "Titel"; Application->Name = "Application"; Application->CreateForm(__classid(TMainForm), &MainForm); Application->Run(); } catch (Exception &exception) { Application->ShowException(&exception); } return 0; }MyClass stellt einen globalen Zeiger auf die Klasse zur Verfügung, über den dann verschiedene Komponenten (sind auf den Fenstern plaziert) auf MyClass zugreifen können. Nur beim Beenden gibt es Probleme, weil dann scheinbar MyClass nicht mehr gültig ist, aber die Destruktoren der Komponenten noch aufgerufen werden.
Gibt es vielleicht eine Möglichkeit, das Schließen der Fenster zu erzwingen?
Vielen Dank im Voraus.
Rob'
-
Was für Probleme gibt es? Schutzverletzung , Absturz?
Die Anwendung wird nach return 0 endgültig geschlossen, da werden noch einige Aufräumarbeiten von der C++ Laufzeitungebung durchgeführt und danach wird der Prozess von Windows entfernt.
Du kannst ja auch mal versuchen, deine Klasse dynamisch anzulegen, da behälst du auf jeden Fall die Kontrolle darüber, wann die Klasse erzeugt und auch wieder freigegeben wird.
[code] TMyClass *pmyclass = new TMyClass(); TMyClass &myclass = *pmyclass; try { Application->Initialize(); Application->Title = "Titel"; Application->Name = "Application"; Application->CreateForm(__classid(TMainForm), &MainForm); Application->Run(); } catch (Exception &exception) { Application->ShowException(&exception); } delete pmyclass; return 0; } [/code]
-
Danke für deine schnelle Antwort.
Dynamisches Erzeugen hilft leider auch nicht, da die Aufräumarbeiten erst nach dem delete von myclass erledigt werden. Und beim Aufräumen werden auch die Destruktoren der Komponenten auf den Forms aufgerufen, d.h. es erfolgen auch noch Zugriffe auf myclass bzw. Zugriffe ins Leere.
Rob'
-
Dann würde ich in den Destruktoren prüfen, ob dein TmyClass objekt noch gültig ist, dafür müßtest du dann aber auf die einzelnen Methoden über den Zeiger -> zugreifen, also statt
[code] myclass.Methode();[/code]
dann[code] pmyclass->Methode();[/code]
schreiben.Weiterhin gehört noch nach dem "delete pmyclass" noch:
[code] pmyclass=0;[/code]
Dann mußt du nur die Prüfung auf Gültigkeit durchführen:
[code] if (pmyclass) { pmyclass->HierDeineMethode(); } [/code]Edit: Wenn du es "ganz böse"
machen willst, lässt du das[code] delete pmyclass; pmyclass=0; [/code]einfach weg. Dann hast du zwar ein Speicherleck, aber wenn dein Prozess sowieso komplett beendet wird, räumt Windows das dann auf, aber es ist nicht die feine englische Art.

-
Die letzte Variante funktioniert, ist mir aber sehr suspekt. Das Objekt ist ja eigentlich nicht mehr gültig, sondern nur der Code hängt noch im Speicher. Das sind weitere Merkwürdigkeiten zu erwarten...
Deine anderen Vorschläge würden die Abstürze beim Beenden verhindern, aber das ist nicht das, was ich eigentlich will: Ich will in den Destruktoren noch einmal auf MyClass zugreifen.
Mir schwebte als Lösung eher etwas wie die Koordinierung der Beendigungsreihenfolge vor. Oder ein erzwungenes Schließen der Fenster, bevor winmain beendet wird und solange MyClass noch gültig ist.
Erbitte weitere Vorschläge.
Danke
Rob'
-
Tja, setz Dir mal einen Haltepunkt in den Destruktor eines Forms und auf das return 0 in der project.cpp. Fällt Dir was auf?
Mach das Objekt am besten innerhalb des MainForms (private) und schreib ne Gettermethode dazu...
Falls Du aber zur masochistischen Art gehörst und weiterhin mit Problemen rechnen willst, reicht es, das Objekt vor der WinMain zu erzeugen, dann ist es während des Destruktoraufrufs noch gültig...
-
Tja, setz Dir mal einen Haltepunkt in den Destruktor eines Forms und auf das return 0 in der project.cpp. Fällt Dir was auf?
Das ist das Problem: Die Formulare werden erst mit TApplication entfernt, und TApplication wird erst nach Beendigung von winmain entfernt.
Da bin ich doch eher masochistisch veranlagt.

Kennt jemand noch eine "saubere" Lösung?
Rob'
-
Irgendwie scheinst Du meinen Post falsch interpretiert zu haben (zufaulzumeinloggen == Joe_M.).
Da stehen doch zwei Lösungsmöglichkeiten. Die 'schmutzige' wäre, das Objekt bereits vor der WinMain zu erzeugen, die 'saubere' wäre, das Objekt im MainForm zu erzeugen und zu verwalten und den anderen Formularen über eine Methode einen Zeiger auf das Objekt bereit zu stellen.
-
Die "saubere" Lösung wollte ich gern vermeiden. Ursprünglich war MyClass eine Komponente (plaziert auf dem Hauptformular), auf die von mehreren Komponenten auf verschiedenen! Forms zugegriffen wurde. Die Koordination mit Notification usw. macht aber einen Haufen Arbeit und wird schnell unübersichtlich. Deshalb habe ich das Ganze auf eine Klasse mit einem global gültigen Zeiger umgestellt.
Ich habe jetzt folgenden Code ohne Absturz beim Beenden:
MyClass myclass; WinMain(... { try .. .. return 0; }Ein Erzeugen mit new innerhalb von WinMain ohne delete am Ende (siehe Post von Burkhi) funktioniert allerdings auch. Deshalb jetzt meine Frage: Wie lange ist denn nun das außerhalb erzeuge Objekt gültig, bzw. ist es länger gültig als TApplication, was ja auch erst nach Beendigung von WinMain zerstört wird?
Rob'
-
Bei globalen (statischen) Daten kannst du dir nie sicher sein, in welcher Reihenfolge sie erzeugt bzw. zerstört werden (meistens kommt es auf die Reihenfolge der Dateien beim Linken an).
Du solltest also keine Abhängigkeiten zwischen verschiedenen globalen Objekten schaffen (niemals -) - das gibt nur Ärger.Du solltest evtl. eine Destroy-Funktion von Hand aufrufen (am Ende der WinMain).
-
Bei letzter Variante, also Objekt außerhalb von WinMain, läuft zwar die Anwendung, allerdings stürzt der Builder beim Beenden ab bzw. ich erhalte Schutzverletzungen beim Schließen des Projektes.
Rob'
-
Ich würde dir die Variante vorschlagen, die ich dir schon einmal gezeigt hatte , nämlich zu prüfen, ob denn das Klassenobjekt noch existiert, schau dir dazu doch bitte nochmal den 3 . Post an.
Es müßte ja reichen, wenn du die Prüfung in den Destruktoren vornimmst, bzw. in FormDestroy.

Edit : Und "das böse" machst du dann nicht.

-
Wir sind doch alle gern mal böse

Die Prüfung könnte ich schon machen, aber wenn das Ergebnis dann so ausfällt, dass mein globales Objekt schon zerstört wurde, können auch meine Komponenten ihre abschließende Aktion über dieses Objekt nicht mehr ausführen.
Rob'
-
Ich glaube, ich habe eine Lösung gefunden:
void __fastcall startup_function() { new TMyClass(); // globale Variable MyClass wird initialisiert } void __fastcall exit_function() { delete MyClass; } #pragma startup_function #pragma exit_functionMit Hilfe der beiden pragma-Anweisungen ist es möglich, dem Linker 2 Funktionen mitzuteilen, die ganz am Anfang bzw. ganz zum Schluß ausgeführt werden. Bis jetzt erhalte ich keinerlei Fehlermeldungen.

Rob'
PS: Und wir müssen auch nicht böse sein.
