H1 I have written a little process to save data before Application.Terminate
using OnCloseQuery
. I was wondering whether this is sufficient in the event of a power failure or a computer crash.
type
TForm1 = class(TForm)
abs: TABSDatabase;
ABSTable1: TABSTable;
....
ABSTable6: TABSTable;
....
var
Form1: TForm1;
isBusy : Boolean;
....
procedure TForm1.CloseTables;
var
x : Integer;
dummy : TABSTable;
begin
for x:=0 to ComponentCount-1 do
begin
if Components[x] is TABSDataSet then
begin
if Components[x] is TABSTable then
begin
dummy := (Components[x] as TABSTable);
if ((dummy.Active = True) and ((dummy.state = dsEdit) or (dummy.State = dsInsert))) then
begin
dummy.Post;
dummy.Active := False;
end
else
if dummy. Active = True then dummy.Close;
end;
end;
end;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
if abs.Connected = True then isBusy := True else isBusy := False;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if isBusy = True then
begin
CanClose := False;
CloseTables;
abs.Connected := False;
isBusy := False;
Application.Terminate;
end
else CanClose := True;
end;
Thank you in advance.
Edit
I modified my code following David Heffernan's advice.
procedure TForm1.CloseTables;
var
x : Integer;
dummy : TABSTable;
begin
for x:=0 to ComponentCount-1 do
begin
if Components[x] is TABSDataSet then
begin
if Components[x] is TABSTable then
begin
dummy := (Components[x] as TABSTable);
if ((dummy.Active) and ((dummy.state = dsEdit) or (dummy.State = dsInsert))) then
begin
dummy.Post;
dummy.Active := False;
end
else
if dummy.Active then dummy.Close;
end;
end;
end;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if abs.Connected then
begin
CanClose := False;
CloseTables;
abs.Connected := False;
Application.Terminate;
end
else CanClose := True;
end;
CodePudding user response:
this is sufficient in the event of a power failure or a computer crash
No, not at all.
After answering that question let's take a look where OnCloseQuery
is triggered at all, so you can sense what else you might miss:
- (At least in Delphi 5) It is invoked when the Windows session was about to end and every running process was asked to close gracefully:
procedure TCustomForm.WMQueryEndSession(var Message: TWMQueryEndSession); begin Message.Result := Integer(CloseQuery and CallTerminateProcs); end;
The
WM_QUERYENDSESSION
message is sent when the user chooses to end the session or when an application calls one of the system shutdown functions. If any application returns zero, the session is not ended. - When
.Close()
is called - the typical call to close one of your windows (forms). - When internally
.CloseModal()
is called.
Keep in mind that something as easy as TerminateProcess()
will kill your running program without letting it any chance of still executing instructions. Furthermore using SuspendThread()
on your main program's thread can also hang it right there infinitly, so your code isn't executed either.
CodePudding user response:
A comment was made that nothing can help if you lose power or the computer crashes. That is not completely correct. But the only things that can help in such cases are:
- A UPS (Uninterruptible Power Supply), as David Heffernan mentioned (which will only help in the case of a power failure).
- Saving data periodically instead of waiting for the form or application to close.
In the latter case, there are two potential problems:
- You will still lose any unsaved data since the last periodical save (which will be minimised if you save frequently).
- The power fails or the computer crashes during a periodical save. Depending on your requirement this might be an acceptable risk, but the way to avoid this problem is to save in a different place each time, perhaps deleting the previous periodical save after the latest periodical save has successfully completed.
As I have not used databases, I cannot say how that should be done with databases.