Recent

Author Topic: Terminate Application  (Read 2903 times)

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Terminate Application
« on: June 21, 2023, 08:20:01 am »
Hello,

what happens after i call Application.terminate ?

i have this code:
Code: Pascal  [Select][+][-]
  1.  procedure TStartUp.FormCloseQuery(Sender: TObject; var CanClose: boolean);
  2. begin
  3.    if CanClose then begin
  4.       //save config
  5.       Config.Save;
  6.  
  7.       FreeAndNil(fMyObject);
  8.  
  9.       Application.Terminate;
  10.    end;
  11. end;
  12.  

and in an Image on my MainForm i have this MouseMove Event Handler

Code: Pascal  [Select][+][-]
  1. procedure TStartUp.DrwMouseMove(Sender: TObject; Shift: TShiftState; X,
  2.  Y: Integer);
  3. begin
  4.    fMyObject.CheckSomething(X, Y);
  5. end;
  6.  

i get an Access Violation after the Application is Terminated. The Code in the MouseMove Procedure gets still executed after calling Application.Terminate.
How can i prevent this ?

thanks in advance !

Zvoni

  • Hero Member
  • *****
  • Posts: 3361
Re: Terminate Application
« Reply #1 on: June 21, 2023, 08:46:02 am »
Hello,

what happens after i call Application.terminate ?

i have this code:
Code: Pascal  [Select][+][-]
  1.  procedure TStartUp.FormCloseQuery(Sender: TObject; var CanClose: boolean);
  2. begin
  3.    if CanClose then begin
  4.       //save config
  5.       Config.Save;
  6.  
  7.       FreeAndNil(fMyObject);
  8.  
  9.       Application.Terminate;
  10.    end;
  11. end;
  12.  

and in an Image on my MainForm i have this MouseMove Event Handler

Code: Pascal  [Select][+][-]
  1. procedure TStartUp.DrwMouseMove(Sender: TObject; Shift: TShiftState; X,
  2.  Y: Integer);
  3. begin
  4.    fMyObject.CheckSomething(X, Y);
  5. end;
  6.  

i get an Access Violation after the Application is Terminated. The Code in the MouseMove Procedure gets still executed after calling Application.Terminate.
How can i prevent this ?

thanks in advance !

Untested
Code: Pascal  [Select][+][-]
  1. procedure TStartUp.DrwMouseMove(Sender: TObject; Shift: TShiftState; X,
  2.  Y: Integer);
  3. begin
  4.    If Assigned(fMyObject) Then fMyObject.CheckSomething(X, Y);  // Or If fMyObject<>Nil Then....
  5. end;
  6.  
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Terminate Application
« Reply #2 on: June 21, 2023, 08:49:32 am »
Also untested but have you considered using the FreeAndNil(fMyObject); in the actual onclose event instead of the query ? (perhaps not possible for your situation (I can not tell from the snippet posted).

Interesting location to call terminate ... *

* I mean that usually you set the variable CanClose in the oncloseqeury to force the close (based on any condition that your app want to use).
« Last Edit: June 21, 2023, 08:51:49 am by TRon »
Today is tomorrow's yesterday.

Josh

  • Hero Member
  • *****
  • Posts: 1455
Re: Terminate Application
« Reply #3 on: June 21, 2023, 08:55:56 am »
hi

application.terminate is not immediate, its sends message wm_quit to allow the application to quit in an orderly way.

you could create a global var that may help.
ie

Code: Pascal  [Select][+][-]
  1. Var Exiting_Now:Boolean = False;

then in your closequery
Code: Pascal  [Select][+][-]
  1. Config.Save;
  2. Exiting_Now:=true;
  3. FreeAndNil(fMyObject);
nb Ideally the tidying up of your created object, threads etc should be in the close event, the query is a means to allow the user to have the option of closing the app or not; hense the canclose var

and in your mouse move
Code: Pascal  [Select][+][-]
  1. if not Exiting_Now then fMyObject.CheckSomething(X, Y);
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Terminate Application
« Reply #4 on: June 21, 2023, 09:01:36 am »
Quote
Untested
Code: Pascal  [Select][+][-]
  1. procedure TStartUp.DrwMouseMove(Sender: TObject; Shift: TShiftState; X,
  2.  Y: Integer);
  3. begin
  4.    If Assigned(fMyObject) Then fMyObject.CheckSomething(X, Y);  // Or If fMyObject<>Nil Then....
  5. end;
  6.  

that would solve this certain problem, but i realy would like to understand what and why this happens.

Also untested but have you considered using the FreeAndNil(fMyObject); in the actual onclose event instead of the query ? (perhaps not possible for your situation (I can not tell from the snippet posted).

* I mean that usually you set the variable CanClose in the oncloseqeury to force the close (based on any condition that your app want to use).

i do not have anything in the OnClose Handler. I use the CloseQuery handler to prevent the user from exit without saveing.
Does OnClose get called after the CloseQuery ?

Quote
Interesting location to call terminate ... *

i think the Application.Terminate should be executed at the very end, isn't that the Case here ?
as far as i know, OnClose itself calls Application.Terminate because its my MainForm right ? so it would not even be needed.
But with or without the Application.Terminate, i still get this Access violation.

if i do
Code: Pascal  [Select][+][-]
  1. DRW.Enabled:= false;
  2.  

then i run into a "endless Loop" and the Application wont terminate


Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Terminate Application
« Reply #5 on: June 21, 2023, 09:07:06 am »
i moved oll of the Freeing stuff into the OnClose handler and only left the query with the Checks if i can close.

Code:
Code: Pascal  [Select][+][-]
  1.  
  2. procedure TStartUp.FormCloseQuery(Sender: TObject; var CanClose: boolean);
  3. begin
  4.    if CheckForSave then
  5.       CanClose:= false
  6. end;
  7.  
  8. procedure TStartUp.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  9. begin
  10.    Config.Save;
  11.    FreeAndNil(fDrawArea);
  12. end;
  13.  


i was thinking that the OnClose / OnCloseQuery handler are the final code that get Executed. I am realy not sure on how to handle this.
« Last Edit: June 21, 2023, 09:10:20 am by Weitentaaal »

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Terminate Application
« Reply #6 on: June 21, 2023, 09:10:44 am »
that would solve this certain problem, but i realy would like to understand what and why this happens.
In the canclose event your form is still active. That means that the events are still called (or can be called).

Quote
i do not have anything in the OnClose Handler. I use the CloseQuery handler to prevent the user from exit without saveing.
Does OnClose get called after the CloseQuery ?
Yes. That is if the canclose variable is true then onclose event gets fired hence my suggestion.

Quote
i think the Application.Terminate should be executed at the very end, isn't that the Case here ?
No. Not really. If you have only one last form left (mainform) and it is closed then your application will 'terminate' gracefully (without the need to call application Onterminate).

i was thinking that the OnClose / OnCloseQuery handler are the final code that get Executed. I am realy not sure on how to handle this.
That second solution you posted is at least a bit more sane. In the onclose you check if data is saved. perhaps call a dialog for the user to answer and depending on the answer and or success of saving the data you set/unset the canclose variable to either true or false.

The actual last code that gets called (not considering unit intialization/finalization) is the form's destroy event. That would in theory even be a better place to free your object (but it depends on how long the objects needs to be active, in this location it is the last place where you are able to free it when considering the normal flow of events of a form).
« Last Edit: June 21, 2023, 09:17:05 am by TRon »
Today is tomorrow's yesterday.

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Terminate Application
« Reply #7 on: June 21, 2023, 09:20:12 am »
Quote
That second solution you posted is at least a bit more sane. In the onclose you check if data is saved. perhaps call a dialog for the user to answer and depending on the answer and or success of saving the data you set/unset the canclose variable to either true or false.

The actual last code that gets called (not considering unit intialization/finalization) is the form's destroy event. That would in theory even be a better place to free your object (but it depends on how long the objects needs to be active, in this location it is the last place where you are able to free it when considering the normal flow of events of a form).

ok so if i leave it like this then i would still need  to check if the Object is Assigned right  ?
« Last Edit: June 21, 2023, 09:21:43 am by Weitentaaal »

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Terminate Application
« Reply #8 on: June 21, 2023, 09:21:51 am »
ok so if i leave it like this then i would still need  to check if the Object is Assigned right ?
That is why I wrote "untested". please check. If it still gives you an access violation then set the onmousemove event to nil in the formclose just before the freeandnil (in which case you can omit the check in the onmouseevent).

I do not know the (closing) event order from memory and sometimes I struggle with the same issue. There is a wikipage but it doesn't really tell us when exactly the mousemove event is not fired anymore by normal flow of events.
« Last Edit: June 21, 2023, 09:31:54 am by TRon »
Today is tomorrow's yesterday.

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Terminate Application
« Reply #9 on: June 21, 2023, 09:37:04 am »
That is why I wrote "untested". please check. If it still gives you an access violation then set the onmousemove event to nil in the formclose just before the freeandnil (in which case you can omit the check in the onmouseevent).

I do not know the (closing) event order from memory and sometimes I struggle with the same issue. There is a wikipage but it doesn't really tell us when exactly the mousemove event is not fired anymore by normal flow of events.

Ok, i tried and still got AV.
thank to all of you guys. it's more understandable for me now.

Edit:
after reading this:
Quote
OnCreate => OnShow => OnActivate => OnPaint => OnResize => OnPaint => ...
OnCloseQuery => OnClose => OnDeactivate => OnHide => OnDestroy

i do not get AV when i move it into OnDestroy handler.
« Last Edit: June 21, 2023, 09:43:30 am by Weitentaaal »

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Terminate Application
« Reply #10 on: June 21, 2023, 09:55:49 am »
@Weitentaaal:
Note that you have two different things going on.
1) you want to save your data.
2) you get an AV due to the onmousemoveevent

1 depends on whether or not your onmousemove event collects data that needs to be saved in/with your data. If they are unrelated then they are really two separate things (and you could use your original idea/implementation)

2) has to do with the fact that somewhere in your code you create/assign the object but release/nil it too soon in that the onmousemove event still gets invoked where you expect it not to be fired anymore.

regarding 2, if you assign/create the object in the oncreate event of your form then the usual order of events (at least that I try to maintain) is use the ondestroy event to release such an object. I usually use events that comes in pairs such as onShow/OnHide OnCreate/OnDestroy etc. as long as there is need for both creation/destruction.

I do not always use that flow because sometimes you are in a situation that some object is only required "on the fly". In such situation i create the object, let it live for as long as is required and at the first possible moment free it again. If for whatever reason that is impossible then i Use the ondestroy event as last resort to free the objects that where created during the Life of the/a form.
Today is tomorrow's yesterday.

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Terminate Application
« Reply #11 on: June 21, 2023, 11:07:33 am »
1 depends on whether or not your onmousemove event collects data that needs to be saved in/with your data. If they are unrelated then they are really two separate things (and you could use your original idea/implementation)

The MouseMove event is used to convert X, Y Coordinates to x, Y, Z Coordinates. i display a coordinate-System in the Image. I need to know where the user clicks, and then react to those clicks.

Quote
2) has to do with the fact that somewhere in your code you create/assign the object but release/nil it too soon in that the onmousemove event still gets invoked where you expect it not to be fired anymore.

At this point in my Code i do not need that Object anymore, i did not expect it to fire at this point.

Quote
regarding 2, if you assign/create the object in the oncreate event of your form then the usual order of events (at least that I try to maintain) is use the ondestroy event to release such an object. I usually use events that comes in pairs such as onShow/OnHide OnCreate/OnDestroy etc. as long as there is need for both creation/destruction.

i do create it in the OnCreate

Quote
I do not always use that flow because sometimes you are in a situation that some object is only required "on the fly". In such situation i create the object, let it live for as long as is required and at the first possible moment free it again. If for whatever reason that is impossible then i Use the ondestroy event as last resort to free the objects that where created during the Life of the/a form.

i try to do that aswell.

Thanks for the hints ! much appreciated.

 

TinyPortal © 2005-2018