A typical application looks like this:
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
After Run() what happens from what I could see, it waits to handle all message loop events and after that Running property is set to false. However, form is not yet destroyed until the very program end.
After comment by David Heffernan I've revised the question:
How can I ensure that the forms have been destroyed after Run() or how can I destroy a form which has been created by CreateForm? Is there a DestroyForm() or similar equivalent?
How can I ensure that the forms have been destroyed after Run()
The VCL ensures that for you. CreateForm() sets the Application as the form's Owner. When the Application object is freed by the VCL's cleanup logic after WinMain() exits, it will free everything it owns.
how can I destroy a form which has been created by CreateForm?
If you want to free it manually, you can simply delete it:
delete Form1;
The form will remove itself from its Owner so it is not freed a second time.
Is there a DestroyForm() or similar equivalent?
No, nor is one needed. Simply delete it as if you had created it with new instead of CreateForm().
Your form is not explicitly destroyed. And so its lifetime is determined by its owner. When its owner is destroyed, it is destroyed. The owner is Application which is destroyed in the VCL unit finalization stage. And so your form is destroyed then too.
You wish to know how to destroy a form before it is automatically destroyed by its owner. That is simple: just destroy it when you require it to be destroyed.
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
delete Form1;
Related
In this question, Remy said in a comment that:
the HWND provided by the TWinControl.Handle property is not persistent. It can get destroyed and recreated during a component's lifetime, even multiple times. Every time the TShellListView gets a new HWND assigned, you have to call DragAcceptFiles(TRUE) again. Overriding CreateWnd() allows you to do that. For good measure, you should also override DestroyWnd() to call DragAcceptFiles(FALSE) before the HWND is destroyed.
I wasn't aware of that until now and I want to understand the mechanism that destroy and recreate the HWND. What are the cases when this is happening and why ?
I am new to Delphi and my question may be very basic.
I created a Form in a Delphi procedure. Until now, I was using ShowModal() and then freeing all the objects that I want to avoid leaking after closing the Form.
Now, I would like to show the Form modeless, but I don't know how I can free the objects inside the OnClose event.
Does anybody know a solution for it?
Simply set the Action parameter to caFree:
procedure TMyForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
Per the documentation:
The value of the Action parameter determines if the form actually closes. These are the possible values of Action:
caNone
The form is not allowed to close, so nothing happens.
caHide
The form is not closed, but just hidden. Your application can still access a hidden form.
caFree
The form is closed and all allocated memory for the form is freed.
caMinimize
The form is minimized, rather than closed. This is the default action for MDI child forms.
Setting Action to caFree will cause the Form to call Release() on itself after the OnClose handler has exited:
Destroys the form and frees its associated memory.
Use Release to destroy the form and free its associated memory.
Release does not destroy the form until all event handlers of the form and event handlers of components on the form have finished executing. Release also guarantees that all messages in the form's event queue are processed before the form is released. Any event handlers for the form or its children should use Release instead of Free (Delphi) or delete (C++). Failing to do so can cause a memory access error.
Note: Release returns immediately to the caller. It does not wait for the form to be freed before returning.
Release() posts a delayed CM_RELEASE message to the Form window. Once execution flow returns to the main message loop and the message is dispatched, the Form will free itself from memory.
If your TForm object owns other objects, they will be freed automatically when the TForm is freed.
You can also
for each dynamically created object do
Object.Free;
Current Delphi versions (Since Xe) documentation recommends to use new approach
Object.DisposeOf;
This new approach works optimized in multi-device application (different operational system)
I've read a LOT of stuff lately regarding this, but never found a final answer.
So, for example if I write:
Form1 := TForm1.Create(Application);
the aplication should be responsible for freeing the form from memory right?
why then people usually do as follows:
Form1 := TForm1.Create(Application);
Form1.ShowModal;
Form1.Free;
??
Saw in some places that if you try to "free" an object that was already freed you would get an EAccessviolation msg, but as I tested it is not always true.
So PLEASE, How this actually works??
This EAccessviolation thing is driving me crazy, how can I understand this thing completely?? where do I find this precious information!??
The general rules are:
If you're going to free it yourself, use nil as the owner.
If you're not going to free it yourself, assign an owner that will take the responsibility to free it.
So, if your code is something like this:
Form1 := TForm1.Create(...)
Form1.ShowModal;
Form1.Free;
You should write it with nil as the owner, and protect it in a try..finally block:
procedure TForm1.Button1Click(Sender: TObject);
var
AForm: TForm2;
begin
AForm := TForm2.Create(nil);
try
AForm.ShowModal;
finally
AForm.Free; // You know when it will be free'd, so no owner needed
end;
end;
If on the other hand, you're going to leave it around for a while, assign an owner that can take care of freeing it later:
procedure TForm1.Button1Click(Sender: TObject);
var
AForm: TForm2;
begin
AForm := TForm2.Create(Application);
// Here you don't know when it will be free'd, so let the
// Application do so
AForm.Show;
end;
Neither of these techniques will cause an access violation if done the way I've demonstrated here. Note that in both cases, I did not use the IDE-generated Form2 variable, but used a local one instead to avoid confusion. Those IDE-generated variables are evil (except for the required Form1 or whatever you name it that represents the main form, which must be auto-created and owned by the Application). Other than the var for the main form, I always delete that auto-generated variable immediately, and never auto-create anything except possibly a datamodule (which can be autocreated before the main form without any problem, as a datamodule cannot be the main form).
The task of a component's Owner is to destroy all owned components when you the owner are being destroyed.
The Application object is destroyed upon termination and so if you are relying on it to destroy your form, that won't happen until termination.
The key point here is the assigning an owner controls both who destroys the owned component, but also when it is destroyed.
In your case you have a modal form that you want to have a short life. Always write them like this:
Form := TMyModalForm.Create(nil);
try
Form.ShowModal;
finally
Form.Free;
end;
There's no point giving them an owner since you explicitly destroy it. And make sure that Form is a local variable.
It won't hurt particularly if you did pass an owner. It would just be wasteful as the owner was notified of its responsibility, and then notified that it was no longer responsible.
But if you did this:
Form := TMyModalForm.Create(Self);
Form.ShowModal;
then each time you showed the modal form you'd leak a form that would not be destroyed until the owning form was destroyed. If you made Application the owned, the modal forms would be leaked until termination.
Ownership between forms is reasonable for, say, the main form and a modeless relative that lives as long as the main form. The modeless form can be owned by the main form and then destroyed automatically when the main form is destroyed.
But if the main form holds a reference to the modeless form then I'd probably just have it unowned and explicitly destroyed from the main form's destructor.
#dummzeuch makes the good point that if you set Position to poOwnerFormCenter, then the framework expects you to provide a form as the owner. In my view, this is a poor design which conflates lifetime management with visual layout. But that is the design, so you are compelled to go along with it. There is though nothing to stop you explicitly destroying an owned component. You can do this:
Form := TMyModalForm.Create(Self); // Self is another form
try
Form.Position := poOwnerFormCenter;
Form.ShowModal;
finally
Form.Free;
end;
When you destroy the form, its owner is notified, and the destroyed form is removed the owner's list of owned components.
The main form itself is interesting. It has to be owned by Application since the main form has to be created by calling Application.CreateForm. That's the only time you should call Application.CreateForm. And the main form is usually the only form you should have owned by Application. Especially if you adopt the policy of having other forms unowned, or owned by the forms that spawn them.
But if you let the main form be destroyed at termination, when Application is destroyed, then you can bee caught out. I've experienced intermittent runtime errors at termination when coded that way. My remedy is to explicitly destroy the main form as the final act of the main .dpr file's body. That is, destroy the main form after Application.Run returns.
The only way I see is to add flag for this, but is this the best way?
When the form is destroyed and I check if(Assigned(form2)) the result is true? Why?
What is the way to do this?
You can use Form1.Showing to see if a form is closed or not.
Just closing a form does not free it unless you set Action := caFree in OnClose event. Default is caHide.
Wow, a blast from the past :)
The way that Assigned() works, is that it basically does nil check on the pointer. If you destroy form2, there will still be a memory address that form2 points to.
I has been a very long time since I've done any Delphi, but from memory, you need to manually set the form2 var to nil when it is destroyed. If you have a central place (eg. a form broker?) where you create & destroy forms, this should be quite easy.
If you use Form1.Free or Form1.Destroy, Delphi will destroy the object but wont set the object reference to nil. So instead use FreeAndNil.
For more information, check Andreas Rejbrand answer in this link
Faced with the same issue when doing some routine on closing application. In this case all forms are destroyed behind the stage but pointers are not set to nil. This code helphs me:
procedure TMyForm.FormDestroy(Sender: TObject);
begin
MyForm:=nil;
end;
So pointer becomes nil and I can check it with Assigned or compare to nil.
Just as a tip, the correct way to do it in some special cases is to create a timer that do the nil assign to the variable.
I will explain it (somehow it is complex), if you create your form within your own code MyForm:=TMyForm.Create and you have a MyFrom.Close it is very easy, just add a MyForm:=nil or also better MyForm.FreeAndNil... but sometimes the reference is not anyware.
Sample: You create inside a procedure, on a loop a lot of copies of the same form (or just one), let the form open and end that procedure, now the reference to the opened form is nowhere, so you can not assign nil or do a freeandnil, etc., in a normal way.
For that cases, the trick is to use a timer (of just one milisecond) that do it, that timer needs the reference, so you must store on a global like the reference to Self, all that can be done on the on close event.
The easiest way to do the free (when no reference anywhere) is to create a TObjectList on the main form, so it will hold all form references that needs to be free, and define a timer (one milisecond) that will go through that list doing the freeandnil; then on the onlcose you add Self to that list and enable that timer.
Now the other part, you have a normal form that is auto created on start, but you need to set it to nil and re-create it on your own code.
That case has a global that point to that form, so you only need to free and nil it, but NOT (i say it loud) on any part inside the own form code, you must do it OUT (i say if loud) of the form code.
Some times you will need to free the form, when user close it, and it is not shown in modal, this case is complex, but again the same trick is valid, on the onclose event you enable a timer (that is out of that form, normally on main form) adn that timer will free and nil. That timer interval can be set as just one milisecond, it will not be run until form has totally closed (please have in mind not using Application.ProcessMessages, that is normally a really bad idea).
If you set Self to nil, free or whatever inside the own form, you can corrupt your application memory (doing that is totally unsafe, not to mention it can eat ram).
The only way to free a form (and nil its reference), a form that is not shown as modal and is the user who close it, is to program a trigger that do that after the form is totally closed.
I know about setting action to do the free, but to set it to nil there is no other safe way.
Must say: If you use timers on your main form, run a Enabled:=False on all of them on the Onclose event... otherwise weird things may occur (not allways, but sometimes... race conditions about destroying application and running code on that timers), and of couse if some one was enabled act correctly to terminate it correctly or abort it, etc.
Your question is one of the complex things to do... free and nil a form that is closed not by code, but by user action.
For all the rest: Think like if the application has at the same time a lot of forms opened and all can interact with the user at the same time (anyone is modal), and you have code that references some of them from the others... you need to know f user has closed any form to avoid accesing that form from code. This is not trivial to be done unless you use timers.
If you have a 'central' form (like an MDI application) you can put that timer on the main MDI form, so any child form that is closed can be freed and nil, the trick is again a timer on that main form.
Only and only if you are sure you can free and nil all non visible forms, you can have a timer on the main form that goes through all forms and if Visible is false, then call FreeAndNil, i consider this way prone to errors, since if you add on a future a form that must not be freed but can stay hidden... this code will not be valid.
Allways remember that if is the user the onw who closes the form that must be freed and nil, there is no way on code to detect and act, no event is launched (after the form is totally closed) and before the form is totally closed you must not even try to free it or nil its reference, weird things can occur (more prone to that if motherboard has more than one socket, also more if your app uses threads, etc).
So, for threaded apps (and also not threaded) i use another method that works great and do not need timers, but need double checking prior to each ThatForm.*, the trick is to define a Form bolean public variable like as PleaseFreeAndNilMe on the public section on the form, then on the onclose (as last line) set it to True and on the OnCreate set it as False.
That way you will know if that form had been closed or only hidden (to hide a form never call close, just call hide).
So coded will look like (you can use this as a warper, instead of defining forms as TForm define them as TMyform, or also better, use a hack like type TForm=class(Forms.TForm) instead of TMyForm=class(TForm) just to have that variable added to all forms):
TMyForm=class(TForm)
...
public
PleaseFreeAndNilMe:=Boolean;
...
procedure TMyForm.FormCreate(Sender: TObject);
begin
PleaseFreeAndNilMe:=False;
...
end;
procedure TMyForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
...
PleaseFreeAndNilMe:=True;
end;
If you preffer hacked version:
TForm=class(Froms.TForm)
public
PleaseFreeAndNilMe:=Boolean;
end;
procedure TForm.FormCreate(Sender:TObject);
begin
inherited Create(Sender);
PleaseFreeAndNilMe:=False;
end;
procedure TForm.FormClose(Sender:TObject;var Action:TCloseAction);
begin
PleaseFreeAndNilMe:=True;
inherited FormClose(Sender,Action);
end;
But as i said, prior to access any member (or just where you do the nil compare) just call a 'global' function passign the reference (no matter if it was nil or not), coded as:
function IsNilTheForm(var TheForm: TMyForm);
begin
if nil=TheForm
then begin // The form was freed and nil
IsNilTheForm:=True; // Return value
end
else begin // The form refence is not nil, but we do not know is it has been freed or not
try
if TheForm.PleaseFreeAndNilMe
then begin // The form is not freed but wants to
try
TheForm.Free;
except
end;
try
TheForm:=Nil;
except
end;
IsNilTheForm:=True; // Return value
end
else begin // The form is not nil, not freed and do not want to be freed
IsNilTheForm:=False; // Return value
end;
except // The form was freed but not set to nil
TheForm:=Nil; // Set it to nil since it had beed freed
IsNilTheForm:=True; // Return value
end;
end;
end;
So where you do if nil=MyForm then ... you can now do if (IsNilTheForm(MyForm)) then ....
That is it.
It is better the timer solution, since form is freed as soon as possible (less ram used), with the PleaseFreeAndNilMe trick the form is not freed until IsNilTheForm is called (if you do not free it any where else).
That IsNilTheForm is so complex because it is considering all states (for a multi socket motherboard and threaded apps) and letting the code free / nil it anywhere else.
Of course, that function must be called on main thread and in atomic exclusion.
Free a Form and Nil its pointer is not a trivial thing, most when user can close it at any time (since no code out of the form is fired).
The big problem is: When a user closes a form there is no way to have a event handler that is triggered out of that form and after the form ends all things it is doing.
Imaigne now that the coder has put a lot of Application.ProcessMessages; every where on the app, also on that form, etc... and has not taken the care for race conditions... try to free and nil such a form after the user asks it to be closed... this is a nightmare, but can be solved with the hacked version of TForm that has a variable that tells that the form has not been freed but wants it.
Now imagine you use hacked TForm and want a normal TForm, just define it as ...= class(Forms.TForm), that way it will now have that extra variable., so calling IsNilTheForm will act as comparing to nil.
Hope this helps VCL coders to FIX such things, like raising an event when an object is destroyed, freed, niled, hide, etc... out of the code of that object, like on main form, etc. That would make live easier... or just fix it... Close and Free implies set to Nil all refences that point to it.
There is another thing that can be done (but i try to allways avoid it): Have multiple variables that point to the exact same form (not to copies ot it), that is prone to a lot of errors, you free one and need to nil all of them, etc... The code i show is also compatible with that.
I know the code is comples... but Free and Nil a form is more complex than my code.
I have some code that does some setup of internal objects in the Loaded() function. However, some external objects are not completely created yet, but are AFTER the Loaded() function is complete. What function does Delphi call after it calls Loaded()?
Better yet what is the creation sequence of a component?
Basically I have a TCP Server and Client. Most people will place those two components into two separate applications, some will place them in the same application for local access.
My Client tries to fetch data from the server in OnLoaded(), but the server may not be up yet! I want to know if another function is called after all the OnLoaded()'s are called.
Loaded is called immediately after the dfm is streamed in, and shouldn't be used to access the server. Your best bet is probably to post a custom message to yourself in the constructor, and have a message handler procedure that responds to that message. Posting the message puts it into the end of the message queue, and therefore it won't get processed until all the other messages ahead of it has been handled. This should delay things long enough for your components to be fully constructed for use.
I've used breakpoints in some components and firmly established that AFTERCONSTRUCTION is called BEFORE LOADED not AFTER.
I've also done the same thing on a FORM and firmly established that AFTERCONSTRUCTION is called AFTER LOADED not BEFORE.
Bear in mind that AfterConstruction is a method in TObject, but Loaded is not. It follows that Loaded is generated by code that may not necessarily put it in a specific order relative to AfterConstruction, since Loaded is not actually part of the construction sequence of a TObject and AfterConstruction is.
Indeed, if you study the RTL source, you will see that Loaded is not even invoked by any self.method of a TComponent, but is in fact invoked by a stream reader that is reading the DFM, and that will most probably be happening under the control of an "owner" component. I strongly suggest therefore that its relationship relative to the execution of AfterConstruction is not really guaranteed. The fact that it appears in a particular order for a form is because the form is most likely the component to initiate stream reading. In other words, it smacks of a convenient accident that Loaded is before AfterConstruction in a form.
Further research shows that NON-FORM components that include the following code may never call the event handler.
procedure Txxx.AfterConstruction; override;
begin
inherited AfterConstruction;
if Assigned(FOnCreate) then FOnCreate(Self);
end;
The reason is that AfterConstruction, if invoked before properties are loaded, will find FOnCreate has not been assigned yet!
In such cases, you really HAVE to use the following:
procedure Loaded; override;
begin
inherited Loaded;
if assigned(OnLoaded) then OnLoaded(self);
end;
Like I said, this will produce different outcomes for a component owned by a form than it would for the form itself! The TForm component is usually the invoker of the DFM stream reader and it is the stream reader that calls Loaded for each component it reads from the form. This process starts (fortunately) BEFORE the form's AfterConstruction, but each component that is loaded by that reader gets its AfterConstruction method called BEFORE its loaded method.
QED.
The great irony is that the Delphi 6 help file says "The AfterConstruction method implemented in TObject does nothing. Override this method when creating a class that takes some action after the object is created. For example, TCustomForm overrides AfterConstruction to generate an OnCreate event."
What it omits to say is that if you try this on anything other than a TCustomForm (which does it already), it doesn't work! Because only a form (which has it already) will load its OnCreate property before calling AfterConstruction. Any other component won't, because the DFM reader invoked by the form calls AfterConstruction before Loaded! A clear case of Borland et. al. not understanding their own code, or at best, writing a help file entry that implies something is possible when in fact it is not.
Note, if your component is not on a form and is created at runtime (even if this is as an "owned" component), its "Loaded" method will NOT be called, because there was no stream reader involved.
Another point of interest is something that "Dr" Bob Swart wrote some time ago about AfterConstruction, namely that it represents the point where virtual methods can be invoked. Evidently this is only partly true: if a form's Loaded method is invoked BEFORE AfterConstruction, then you would not be able to invoke any virtual methods from Loaded if that were true. This is not the case (obviously) because Loaded is itself a virtual method! Evidently, Loaded for a form is called between the constructor and AfterConstruction by the stream reader. It begs the question: by what method is the stream reader actually invoked? My guess is either that it runs under control of the application (not the form) and that it deliberately invokes AfterConstruction differently for a form than for other components, OR that it is the last thing the form's constructor does after having created the VMT and hence the last thing that occurs before AfterConstruction is called in the form. Accordingly all the AfterConstruction-Loaded couplets of components owned by the form are called before the form's AfterConstruction is called. Tracing the calls also shows that mostly AfterConstruction is called for ALL of those components before ALL of their loaded methods are called. I didn't however test the case where there are hierarchical "parents" (such as panels with components on them), so there may be variations on this.
Normally you would override TObject.AfterConstruction for that purpose.
The order of execution is:
each Component.AfterConstruction in creation order
(Form or DataModule).Loaded
each Component.Loaded in creation order
(Form or DataModule).AfterConstruction
Trace:
Debug Output: button AfterConstruction Process Project2.exe (4876)
Debug Output: Form Loaded Process Project2.exe (4876)
Debug Output: button Loaded Process Project2.exe (4876)
Debug Output: Form AfterConstruction Process Project2.exe (4876)
I'm not sure what you mean with
the server may not be up yet
Anyway, if the client and the server are both on the same application form or datamodule, I see alternatives:
You may "force" the system to create the server before the client and up the server in the server's OnLoad and it will be up at the client OnLoad, because documentation says:
When the streaming system loads a form or data module from its form file, it first constructs the form component by calling its constructor, then reads its property values from the form file. After reading all the property values for all the components, the streaming system calls the Loaded methods of each component in the order the components were created. This gives the components a chance to initialize any data that depends on the values of other components or other parts of itself.
Inform the "client" whenever the server is UP to let it initialize (pull data from the server). You can use a direct method call, post a message or whatever you feel comfortable with.
Let the client stand up the server inside it's own OnLoad method.
Why not use the onCreate event of the main Form ?