6
votes

I have a MDI main (parent) form and a MDI child form. I create the child at runtime like this:

VAR
   FrmDereplic: TFrmDereplic;

procedure TMainFrm.Button2Click(Sender: TObject);
begin
 FrmDereplic:= TFrmDereplic.Create(MainFrm);
 FrmDereplic.Show;
end;

Steps to reproduce the error:
I start the app, I press the button to create the child, I press the 'x' button on main (parent) form to close the application and I get an "Cannot create form. No MDI forms are currently active" error.

The line on which the error appears is in the child form:

procedure TFrmDereplic.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action:= caFree;
end;

procedure TFrmDereplic.FormDestroy(Sender: TObject);
VAR MyIniFile: TCubicIniFile;
begin
 MyIniFile:= TCubicIniFile.Create(AppINIFile);
 TRY
  with MyIniFile DO
  begin
   if WindowState<> wsMaximized then
    begin
     // save form's screen pos
     ...
    end;
   WriteInteger  ('Dereplicator', 'fltExtensions', fltExtensions.ItemIndex);  <----- HERE
 FINALLY
  FreeAndNil(MyIniFile);
 END;
end;

I save lots of form's properties (and other's controls properties) to the INI file. But it only fails when I try to save fltExtensions.ItemIndex (which is a TFilterComboBox). If I comment that line it works perfectly.

Any idea why it tries to create a form when I actually closed the application?????????

3

3 Answers

8
votes

I look on some web sites and just found the problem. It looks like it is preferably to have the Owner set to Application, instead of the main form. Remy Lebeau suggests that the real problem is in the OnDestroy of the the child form. There is no valid handle to the window that holds the filter then the OnDestroy is called. So, changing the destruction order gives a chance to TFrmDereplic.OnDestroy to execute properly.

So, here is the solution:

SOLUTION(S)

FrmDereplic:= TFrmDereplic.Create(Application);

or

Do not save form's properties in OnDestroy

The second one requires few extra lines of code as the OnClose even is not always called. This was extracted from Delphi HELP:

Note: When the application shuts down, the main form receives an OnClose event, but any child forms do not receive the OnClose event.

If you use Application.Terminate, then onCloseQuery and onClose will not be called. Same for Halt (but... this is way too extreme, right?).

3
votes

The error occurs when reading the fltExtensions.ItemIndex property because it requires fltExtensions to have an HWND, which requires its parent TFrmDereplic form to have a HWND, which requires the project's MainForm to have an HWND. But the app is in a state of shutdown, and the MainForm cannot allocate its HWND anymore, so TFrmDereplic raises an exception when it cannot obtain an HWND for itself.

Saving your INI data in the form's OnDestroy event is too late. You need to the OnClose event instead.

2
votes

If the code you provided in your question is the real one then I guess the error is in this line:

 FrmDereplic:= TFrmDereplic.Create(TMainFrm);

I never tried this and I am not sure if the compiler really buys it (can't test it now), but you are trying to set a class as owner of the MDI child form. Instead of that you should do either

FrmDereplic:= TFrmDereplic.Create(Application);

or

FrmDereplic:= TFrmDereplic.Create(self);

The first option sets the application as owner of the MDI child form, while the second one sets the instance of the MDI main form as owner.

Hope that helps. :-)