I have a multithreaded application with many forms, but I have to instantiate some classes and call some initialization stuff before the creation of the forms. Of course I have to execute the corresponding finalization code.
Here is a simplified example of .dpr file:
begin // .dpr project file
LoadDlls;
try
Config := TConfig.Create;
try
Application.Initialize;
Application.Title := 'Foo';
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TOtherForm, OtherForm);
//...other forms...
Application.Run;
finally
Config.Free;
end;
finally
UnloadDlls;
end;
end;
The problem here is that the code inside finally
blocks get executed BEFORE the OnDestroy
/ destructor
s of my forms.
This turns clear looking at the finalization
section of Form
unit:
finalization
if Application <> nil then DoneApplication;
And DoneApplication
calls Application.DestroyComponents
which effectively Frees all Application
's owned Forms.
So, Forms created with Application.CreateForm
will be destroyed after any code inside the main begin..end
block.
What I want is that after Application.Run
all the forms are destroyed, so that their OnDestroy
event handlers can see the Config
object and the external functions defined in my dlls. Ditto if an exception is raised.
But I also want to have the standard Application's exception handling if Config.Free
or UnlodDlls
raise (Application must still exist).
Note that:
finalization
block (would it be possible in .dpr?) to keep code clearer and debuggable;I think the simplest solution is to explicitly call Application.DestroyComponents
after Application.Run
. Do you think is there any drawbacks?
Is there a more elegant solution?
Thank you
The cleanest way to achieve what you want is for you to control the destruction of the forms.
The only form that needs to be owned by Application
is your main form. That needs to be so because the first form created by a call to Application.CreateForm
is designated to be the main form. So, my advice is that you should make one call, and one call only to Application.CreateForm
, to create the main form. For all your other forms, create them by calling their constructors. Let the other forms be owned by the main form. When it's time to shut down, destroy the main form, and let it take all the owned forms with it.
You might write your .dpr code like so:
begin
LoadDlls;
try
Config := TConfig.Create;
try
Application.Initialize;
Application.Title := 'Foo';
Application.CreateForm(TMainForm, MainForm);
try
OtherForm := TOtherForm.Create(MainForm);
YetAnotherForm := TYetAnotherForm.Create(MainForm);
Application.Run;
finally
FreeAndNil(MainForm);
// will destroy the other forms since they are owned by the main form
end;
finally
Config.Free;
end;
finally
UnloadDlls;
end;
end;
One other point to make is that perhaps you don't need to unload the DLLs. Since this is clearly an executable, the system will unload them anyway. Why do you need to do so?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With