Search code examples
delphidelphi-7

Access violation while freeing a form in another form's OnDestroy event


I am working on Delphi 7. I am getting access violation error while freeing the form.

1) Create new Application Delphi 7 (Unit1)

2) Add new form (Unit2)

3) For Unit1 uses clause add Unit2 and write below code

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, unit2, StdCtrls;

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

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  form2 : TForm2;
begin
  try
    form2 := TForm2.Create(Application);
    //form2.ShowModal;
  finally
    //FreeAndNil(form2);
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Form2 <> nil then
    FreeAndNil(form2);
end;

end.

4) Run the Application and close Form1 -- Getting below error.

enter image description here

I don't want to free Form2 Object on OnClose or OnCloseQuery, Because i have some code on these events.I want to free Form2 object after OnClose or OnCloseQuery.

why i am getting error and how to fix this?


Solution

  • The problem you describe can be reproduced in Delphi 7, following your steps. The reason for the access violation is that Form2 is autocreated in the .dpr file (and that makes the application the owner of the form), but you also attempt to control its lifetime by calling FreeAndNil(Form2) in the OnDestroy event of Form1. At the time you attempt to free the form, it is already freed by the application.

    It is not really clear, why you attempt to free Form2 when the application (presumably) is about to terminate (since the main form is being destroyed). As the application is the owner you can safely let the application take care of its duties.

    You need to decide, who you want to be the owner of Form2.

    1. If it's going to be you, you should remove Form2 from the list of autocreated forms (see Project - Options - Forms and move Form2 to Available forms).
    2. If you want the application to be the owner, simply don't Free the form, use hide and show methods to control its visibility, if needed, but leave it to the application to destroy it according its design.

    By the way, the code you have in TForm1.FormCreate() has nothing to do with the AV you have seen. That Form2 is a separate instance, and if the intention is to show a splash form, it's ok, as follows:

    procedure TForm1.FormCreate(Sender: TObject);
    var
      form2 : TForm2;
    begin
      form2 := TForm2.Create(nil);
      try
        form2.ShowModal;
      finally
        form2.Free;
      end;
    end;
    

    The form doesn't need an owner, therefore the nil in Create. Since the variable form2 is local, there's absolutely no need to nil it.