How to ensure the execution of the FormClose procedure no matter how the program exits?

In Delphi 7, I have a TMainForm.FormClose procedure, which is designed to write out some status whenever the program exits. This works great when closing a program manually. However, I found that if the program "forcefully" exits Windows (for example, after Windows Update, which requires a reboot), the FormClose procedure is not called.

Edit - I'm new here, and it looks like I can't delete my own post. After some searching, I found a solution .

+4
source share
3 answers

In the above comment, I summed up the answer I found (link) . Basically, it says to provide your own handler for WM_QUERYENDSESSION. This is the recommended code:

procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession); begin inherited; { let the inherited message handler respond first } {--------------------------------------------------------------------} { at this point, you can either prevent windows from closing... } { Message.Result:=0; } {---------------------------or---------------------------------------} { just call the same cleanup procedure that you call in FormClose... } MyCleanUpProcedure; {--------------------------------------------------------------------} end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin MyCleanUpProcedure; end; 

I'm not sure if the Inherited call before the MyCleanUpProcedure call is completely correct. If the Inherited procedure first reverts to Windows, Windows can still close the application before completing MyCleanUpProcedure. I'm not sure what Inherited does for the message WM_QUERYENDSESSION - I assume that by default it allows you to exit immediately. MyCleanUpProcedure is very fast in my application, so it will not force Windows to display the Do Not Respond dialog box due to the lack of response to the WM_QUERYENDSESSION message.

To make sure my procedure is complete, perhaps the procedure should look like this:

 procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession); begin MyCleanUpProcedure; inherited; end; 

Or maybe it?

 procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession); begin MyCleanUpProcedure; Message.Result:=1; // tell Windows it is OK to shut down end; 
+5
source

It is very difficult. If you kill the process from the outside, this is instant termination. There is no chance to clear the period. Rebooting Windows Update often closes the right program by sending it a WM_QUERYENDSESSION message, but it does not always work for some reason. In particular, if your program is delayed for a very long time (asking the user if he wants to save until the exit, for example), then the exit code will kill the process.

So, if you want to guarantee that it will always call this event handler, you will have to guarantee that you will never use a modal dialog box or anything else that blocks the program from starting immediately after receiving WM_QUERYENDSESSION. This is probably more of a problem than worth it.

One option is to do something similar to what Firefox does. Write the status data to a temporary file while it is still running, and then when it reboots, check if this file is there and if the data points to it in the β€œopen” state. If so, your program may know that its last incarnation was somehow killed and take any action, for example, update the status log (or whatever you use) with the latest data available.

+8
source

Information about subsequent actions: I did not know that the inherited procedure did something other than returning "1", so I tried it with both a return and an inherited one. Start my shutdown procedure first, then return 1, then inherited.

 procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession); begin MyCleanUpProcedure; Message.Result:=1; {Signal that it is OK to shut down} inherited; { let the inherited message handler respond } end; 

I tested this code for the case when the system shuts down (manually or due to Windows Update) and my application is still working. The following code has been tested to work correctly in this case - MyCleanUpProcedure really starts before my application closes.

I have not tested this for the case when my application is killed by the task manager - this is not suitable for my application.

+2
source

All Articles