I have a DLL application that is loaded in my main application. The DLL contains a form that is created at runtime. The functionality is: In main application I have a menu which whenever pressed calls a procedure from within the DLL. This procedure dynamically creates the form.
procedure doCreateForm;
var
myForm: TForm1;
begin
myForm := TForm1.Create(nil)
try
...
except
myForm.Free;
end;
end;
The closing procedures:
procedure CloseWindow(ASender: TForm1);
begin
FreeAndNil(ASender);
Application.ProcessMessages;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseWindow(Self);
end;
The problem (access violation) occurs only on the second attempt to create the form. Not first time, not 3rd, 4th, 5th and so on.
So I click on the menu, the form is created (dynamically) and closed (if condition is not satisfied during form create event). I click again on the menu, and when myForm.Create(nil)
is called, AV raises. I click again on the menu, and all is ok. I click again and again and again and all is ok. Only when pressed the 2nd time, AV raises.
Is there something wrong with dynamic creation of visual form in DLL?
A more detailed explanation:
The chain is:
I create MyForm (
myForm := TForm1.Create(nil)
)Prior to showing the form I do some conditioning tests.
If all is ok,
myForm.Show
- this is working fine and I can also close myForm properlyIf something is wrong:
a). I create a message form myMessageForm := TMyMessageForm.Create(nil)
that contains a closing timer (the form closes after 10s). This form has action:=caFree in onClose event
b). I call myForm.Close. This form has also action:=caFree in onClose event - this form closes before myMessageForm closes (due to the timer present in myMessageForm)
Both forms are created with nil owner, but they are connected in some way (I don't know why). and the destruction of forms is not performed correctly. The next time myForm.Create(nil) or myMessageForm.Create(nil) is called, access violation occurs. The myMessageForm should be created independently from myForm and it's destruction should not condition myForm destruction in any way.
unit1;
procedure doCreateForm;
var
myForm: TForm1;
begin
myForm := TForm1.Create(nil)
try
with myForm do
begin
if <test condition true> then Show
else
begin
ShowErrMessage('Error', 'Error message text', errType);
Close;
end;
end;
except
myForm.Free;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
unit2;
procedure ShowErrMessage(title, text: string; err: mtErrType);
var
myMessageForm: TMyMessageForm;
begin
myMessageForm := TMyMessageForm.Create(nil)
try
with myMessageForm do
begin
StepDownCounter := 10;
CloseTimer.Enable := True;
end;
except
myMessageForm.Free;
end;
end;
procedure TMyMessageForm.CloseTimerTimer(Sender: TObject);
begin
StepDownCounter := StepDownCounter - 1;
if (StepDownCounter < 1) then
begin
CloseTimer.Enabled := False;
LabelStepDownText.Visible := False;
Close;
end
else
begin
LabelStepDownText.Caption := 'Window will close in ' + IntToStr(StepDownCounter) + 's';
LabelStepDownText.Visible := True;
end;
end;
procedure TMyMessageForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
Action := caFree;
in yourOnClose
event to free the form. If you were in other event and would like to free the form it-Self
, you'd need to useRelease
. – TLamaAction := caFree
in yourFormClose
event, or useRelease
. – Ken White