views:

563

answers:

6
procedure TMainForm.FormDestroy(Sender: TObject);
var
  Registry: TRegistry;
begin
  Registry := TRegistry.Create;
  try
    Registry.RootKey := HKEY_CURRENT_USER;
    if Registry.OpenKey('...', True) then
    begin
      Registry.WriteInteger('MainLeft', Self.Left);
      Registry.CloseKey;
    end;
  finally
    Registry.Free;
  end;
end;

Similar code works for FormCreate, but not when the application is closed (i.e. nothing is saved to the registry). What am I missing?

P.S. The '...' stands for the registry key name. Since it works for FormCreate, I don't think it's an issue.

P.P.S. If I add MainForm.Destroy to the program code:

begin
  Application.Initialize;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;
  MainForm.Destroy;
end.

nothing changes. If I also set FormDestroy as MainForm's OnDestroy event, I get "Access violation" error upon closing the application.

It's all very confusing :-)

A: 

Try TMainForm.OnCloseQuery instead:

http://delphi.about.com/od/formsdialogs/a/delphiformlife.htm

Bob S
No, the OnCloseQuery and OnClose may fire more than once for a form - they are reversible. OnDestroy is the final exit, and is fine for registry work.
Argalatyr
+1  A: 

OnDestroy is fine for writing to the registry. Something else is going on. What does '...' represent in your code?

Because what you describe sounds like there's a bug somewhere, can you reproduce the problem in a test application?

Argalatyr
Everything else works fine. Including basically the same procedure for FormCreate. It's just that the code doesn't seem to run on FormDestroy.
Mikhail
+2  A: 

The following code works as expected (run the app, click the button 5-10 times to move the mainform to the right, close the app, then run it again and the mainform position is where you left it).

Create a VCL forms application, drop a tbutton on it, size the form so it's just large enough to hold the button, and paste in the following to replace unit1:

unit Unit1;

interface

uses
  Windows, Forms, StdCtrls, Classes, Controls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    procedure InitializeVariables;
    procedure FinalizeVariables;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  registry;

procedure TForm1.Button1Click(Sender: TObject);
begin
  self.Left := self.Left + 10;
end;

procedure TForm1.InitializeVariables;
var
  TheReg : tregistry;
begin
  TheReg := tregistry.Create;
  try
    TheReg.RootKey := HKEY_CURRENT_USER;
    if TheReg.OpenKey('\Software\killme', false) then
    begin
      if TheReg.ValueExists('MainLeft') then
        self.Left := TheReg.ReadInteger('MainLeft');
    end;
  finally
    TheReg.Free;
  end;
end;

procedure TForm1.FinalizeVariables;
var
  TheReg : tregistry;
begin
  TheReg := tregistry.Create;
  try
    TheReg.RootKey := HKEY_CURRENT_USER;
    if TheReg.OpenKey('\Software\killme', true) then
      TheReg.WriteInteger('MainLeft', self.Left);
  finally
    TheReg.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  InitializeVariables;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FinalizeVariables;
end;

end.
Argalatyr
I don't know what's wrong, but your code doesn't work either. Anyway, using FormClose would do. Thanks.
Mikhail
I'm using D2006 under WinXP. Perhaps you're using Vista? Always best to describe your setup when reporting a problem!
Argalatyr
I guess it won't do any harm to write to registry multiple times if FormClose fires more than once. I hope all of this works out for you, in any case.
Argalatyr
Yeah, I'm using Vista and Delphi 7. Didn't know that was relevant. Cheers.
Mikhail
Are you sure the program is not still running? If the process is stil lactive it would explain why OnDestroy hasn't been called yet. See http://stackoverflow.com/questions/1097717/closing-process-of-a-delphi-app-under-vista
mghie
@Argalatyr: inherited doesn't make sense in an event handler.
mghie
@mghie: thanks - I've removed inherited
Argalatyr
@Mikhail: did you attach the form's OnCreate and OnDestroy events to the appropriate methods in my code?
Argalatyr
+3  A: 

Are you actually ever destroying the form?

By default, forms are auto-created, and "closing" them doesn't destroy them, it just hides them.

If you aren't actually calling "MyForm.Free" or setting Action to caFree in the OnClose event, the form is never getting destroyed, and hence the OnDestroy event is never getting fired, and your code is never getting called.

Nick Hodges
+2  A: 

Does your FormDestroy execute at all?

RE: P.S. and P.P.S.

Something else is going wrong in your app. Write a small Delphi program that will access registry in FormDestroy and you'll see that everything is working fine (if not, you'll have a small program that you can post here as a example).

gabr
I already gave him a small app that works for me, and he commented that it doesn't work for him.
Argalatyr
As he doesn't know how to debug an app thing will stay that way, I believe :(
gabr
A: 

OnCreate and OnDestroy are not good places to load/save Registry values that affect the positioning of the window. Override CreateWnd() and DestroyWnd() methods instead. Also, instead of loading/saving individual properties, like Left, use the Win32 API SetWindowPlacement() and GetWindowPlacement() functions instead, which also allows you to load/save maximized/minimized states accurately as well.

Remy Lebeau - TeamB