procedure TForm1.Button1Click(Sender: TObject);

procedure TForm1.Button1Click(Sender: TObject);
begin
try
Form1:=TForm1.Create(nil);
Form1.ShowModal;
finally
FreeAndNil(Form1);
end;
end;
//---------------
everything works just fine at the first time when i click the button when i close it and click the button again i get access violation error at adress 00DB047D
... there is nothing in the OnCreate event for the Form1
... i checked the form if it nil after close it it's says nil
i don't know what i'm doing wrong ,for the record everything was working normal before

Comments

  1. You are freeing the form in a method of the form.

    It seems strange to show an instance of a form inside the method of that same form.

    ReplyDelete
  2. You are using the same variable Form1 for the main form and the secondary form created in the Button1Click event.
    While that is certainly odd, it shouldn't result in an access violation, unless you access Form1 somewhere else.

    ReplyDelete
  3. Thomas Mueller Form1 is not the MainForm ,, yes i'm accessing the form1 from somewhere else lets say Form0 and Form0 isn't The MainForm too

    ReplyDelete
  4. Nick Hodges what do you mean ? how should i free the form ?

    ReplyDelete
  5. You should use a different variable than the default variable that the IDE provides for you:

    procedure TForm1.Button1Click(Sender: TObject);
    var
    MyForm: TForm1;
    begin
    try
    MayForm:=TForm1.Create(nil);
    MyForm.ShowModal;
    finally
    MyForm.Free;
    end;
    end;

    Two points: (1) Never use FreeAndNil (2) Why are you creating a TForm1 inside a TForm1?

    ReplyDelete
  6. the same problem works just for the first time.

    (2) Why are you creating a TForm1 inside a TForm1?
    ...TForm1 inside a TForm1! i don't understand

    ReplyDelete
  7. I am assuming you just started using Delphi: Everytime a TFormX unit is created, a FormX: TFormX global var is also put in place for the IDE to manage automatic form creation. I am sure you are using that Form1 global form from inside your own Form1. Just have a check the advices you got above and check

    ReplyDelete
  8. Joaquin Menemene Not really i checked everything , what if i told you i have 32 Form creating in the same method and everyone of them works just fine expect this form .

    ReplyDelete
  9. Nick Hodges I cannot see any bad thing about FreeAndNil in this context

    ReplyDelete
  10. Hamza Benzaoui The resource protecting pattern is

    foo := TFoo.Create;
    try
    // use foo
    finally
    foo.Free;
    end;

    your code can result in mystic operation

    try
    foo := TFoo.Create; // on exception here
    // use foo
    finally
    foo.Free; // this will be called ... on what?
    end;

    and you should not use the global form variable to store a local instance. That is the root of your problem. The access violation is just a symptom

    ReplyDelete
  11. It was long time ago since we had FreeAndNil fight last time...

    ReplyDelete
  12. Stop using global variables and then come back when you've removed them. Put the try after the resource acquisition.

    When you encounter an error do some debugging. The biggest single weakness in beginners is an inability to debug. That's the next skill you need to acquire.

    ReplyDelete
  13. You wrote:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    try
    Form1:=TForm1.Create(nil);
    Form1.ShowModal;

    1) Form1:= TForm1.Create(nil);
    This is bad:
    a) Form1 is a global. Stop using globals. Here a local scope avoids all confusions.
    b) Form1 could very well be assigned since the event method is a method of TForm1. Now you create a leak.

    2) Instead of writing
    try
    Form1:=TForm1.Create(nil);
    finally

    you must follow this pattern:

    Form1:=TForm1.Create(nil);
    try
    // Some code
    finally

    ReplyDelete
  14. This could be better implemented as a class function:

    class function TForm1.Execute: Boolean;
    var
      F: TForm1;
    begin
      F := TForm1.Create(nil);
      try
        Result := IsPositiveResult(F.ShowModal);
      finally
        F.Free;
      end;
    end;

    ReplyDelete
  15. I agree with the example of Alexander Elagin. Don't place the create inside the try and place it prior. Also, recommend removing the form unit's global Var for the form1: tform1; so that it reinforces use of localized var for form and possible "monkey business" accessing the global from other units.
    In fact, when I create a new form, the first thing I do is delete the global variable.

    ReplyDelete
  16. Thanks a lot guys i figure it out ,, i was referencing to this form in somewhere else i totally forgot it..David Heffernan i know some debugging skills but when it comes to variables and pointers i always get lost and have been avoiding it , but i thinks i should make some time for it . is there any books you can recommend for a deep dive in debugging will be so useful for me thanks in advance :)

    ReplyDelete
  17. Hamza Benzaoui Treat the pointer/reference as a vcard. The variable can hold a vCard (value) and the vcard is pointing to a person/address (instance).

    ReplyDelete

Post a Comment