Ian Branch 127 Posted August 20, 2022 (edited) Hi Team, I run an App inactivity/idle routine in the background. The objective is that if the App is idle, no keyboard or mouse activity for x minutes, the App closes. Closure is generally by closing the Main form. So, I was wondering, what does Delphi do if you are in a second form opened from the main form when the idle triggers? Does it formally/gracefully close the second form first, and by extension any other forms open in the App, then close the main form, or does it simply close the main form and crash the second, and any other, form? I guess a follow up to that, if it does close other forms gracefully first, what dictates the order of closure? Regards & TIA, Ian Edited August 20, 2022 by Ian Branch Share this post Link to post
Uwe Raabe 2057 Posted August 20, 2022 When the MainForm is closed the application is terminated. That implies that all forms created with Application as owner will be destroyed, but not closed (so OnDestroy is called, but not OnClose). The order depends on the components order inside Application. Any form created without an Owner will just vanish. Share this post Link to post
PeterBelow 238 Posted August 20, 2022 Well, closing the main form ends up calling Application.Terminate, which results in a WM_QUIT message posted to the message loop. The reaction to that is to set Application.Terminated to true and fall out of the message loop in Application.Run. After that the Application object proceeds to free all forms and datamodules it ownes in the inverse order of creation. Things are unfortunately not always so clear, though. If a modal form is open it uses its own message loop, which also ends and causes ShowModal to return as if the user cancelled the dialog. Code in the calling method will execute after that until the code flow returns to the main message loop. A further complication are unowned forms. They will get destroyed after the owned forms when the main form window handle is destroyed, as far as I remember, by Windows, since the main form is the API-level owner of all secondary forms. Unowned Forms disconnected from the main form by overriding CreateParams will die last (unless explicitely closed in code executed when another form is destroyed), when the process dies. This usually does not give the form any chance to clean up after itself. So, if you need to have all forms die in an orderly manner you are best served by iterating over Screen.Forms and close each form found explicitely, with the main form last. Share this post Link to post
Ian Branch 127 Posted August 20, 2022 Uwe & Peter, thank you for your responses. I had suspected as much. Peter.. 9 hours ago, PeterBelow said: Screen.Forms and close each form found explicitely, with the main form last. And how does one do that?? I think I have seen that somewhere but I don't recall where. 😞 Is it done from within the MainForm OnClose event? Regards & TIA, Ian Share this post Link to post
Ian Branch 127 Posted August 21, 2022 (edited) Hi Team, I have worked up the following code.. procedure TMainForm.CloseOpenForms; var TheForm: TForm; I: Integer; begin // for I := 0 to Screen.FormCount - 1 do begin TheForm := Screen.Forms[I]; // {$IF Defined(ELogging) or Defined(Codesite)} LogMessage('Form Name = '+ TheForm.Name); {$ENDIF} // if TheForm.Name <> 'MainForm' then TheForm.Close; // end; end; It turns out that MainForm is the first in the order of Screen.Forms so if I don't filter it out I end up in a loop. 🙂 Seems to work well. Open to any suggestions to improve it. Regards, Ian Edited August 21, 2022 by Ian Branch Share this post Link to post
Pat Foley 51 Posted August 21, 2022 2 hours ago, Ian Branch said: It turns out that MainForm is the first in the order of Screen.Forms so if I don't filter it out I end up in a loop. The order of Screen.Forms is last used so you could use downto to avoid the active form at forms[0]. By setting the forms owner to application when creating and only coding FormCloseQuery when necessary allows no need to code the close event of each form. Pat Share this post Link to post
Ian Branch 127 Posted August 21, 2022 (edited) Hi Pat, 27 minutes ago, Pat Foley said: The order of Screen.Forms is last used so you could use downto to avoid the active form at forms[0]. Good point. 27 minutes ago, Pat Foley said: By setting the forms owner to application when creating and only coding FormCloseQuery when necessary allows no need to code the close event of each form. I'm not sure I understand what you are saying here?? I have no special handling in the sub-forms. I have the CloseOpenForms being called in the FormClose of the MainForm. e.g. procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); begin // CloseOpenForms; // Close any open forms. // DBC1.CloseDataSets; // Close any open tables/Queries. // DBE1.Close; // Close the DB Engine // end; In the context of this, is a Datamodule considered a Form? Ian Edited August 21, 2022 by Ian Branch Share this post Link to post
Pat Foley 51 Posted August 21, 2022 I am saying to use FormCloseQuery in the MainForm and not code any FormClose. Any Freeing is done in a FormDestroy. Avoiding the need for troublesome ScreenForm OnClose iteration. Share this post Link to post