-1

I'm trying follow what was suggested in this answer, changing this part of Vcl.Forms.pas:

procedure TCustomForm.CreateWindowHandle(const Params: TCreateParams);
var
  CreateStruct: TMDICreateStruct;
  NewParams: TCreateParams;
begin
  if (FormStyle = fsMDIChild) and not (csDesigning in ComponentState) then
  begin
    {if (Application.MainForm = nil) or
      (Application.MainForm.ClientHandle = 0) then
      raise EInvalidOperation.Create(SNoMDIForm);}
    with CreateStruct do
    begin
      szClass := Params.WinClassName;
      szTitle := Params.Caption;
      hOwner := THandle(HInstance);
      X := Params.X;
      Y := Params.Y;
      cX := Params.Width;
      cY := Params.Height;
      style := Params.Style;
      lParam := THandle(Params.Param);
    end;
    WindowHandle := SendStructMessage(Application.MainForm.ClientHandle,
      WM_MDICREATE, 0, CreateStruct);
    Include(FFormState, fsCreatedMDIChild);
  end
  else

  //...

but still comes the error saying that "no MDI Form is active"

What more is need be made to this suggestion works? Thanks in advance.

Code of test with Forms:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Self); // MDIForm
  Form2.Show;
  Form3 := TForm3.Create(Form2); // MDIChild
  Form3.Show;
end;
FLASHCODER
  • 1
  • 7
  • 24
  • @MartynA, to what i wish above, is better using MDI, of other way, also will be a hack. – FLASHCODER Aug 31 '19 at 20:10
  • @TomBrunberg, i think that no. I made only the introdution and i belived where says: *`"Changing the above code to no longer require the MainForm to be the only fsMDIForm available will solve the problem`"*. But i'm [seeing](https://web.archive.org/web/20171220121543/http://qc.embarcadero.com/wc/qcmain.aspx?d=12006) that have more code below :-). I'll try. – FLASHCODER Aug 31 '19 at 20:51
  • @TomBrunberg, *`"Anyway, you do know that you should do the changes only to a copy of Forms.pas in your project directory, and not to the one in the library."`* yes. I'm following the C++ Builder example linked on question of reference. – FLASHCODER Aug 31 '19 at 21:18
  • 1
    When making edits to RTL/VCL/FMX code, make sure that you 1) *make a copy* of the altered file(s), 2) *add the copies* to your project, and 3) disable "Build with runtime packages" in the project options. Otherwise the edits won't take effect. – Remy Lebeau Aug 31 '19 at 21:21
  • @RemyLebeau, i'm seeing your **MDIChild.cpp** and seems that all changes you made are inside Form MDIChild and not in `Forms.pas`. Are the same Delphi equivalent routines suggested [here](https://web.archive.org/web/20171220121543/http://qc.embarcadero.com/wc/qcmain.aspx?d=12006). Then, where is right to alter? `Form.pas` or on self project (Form MDIChild)? i not understood. – FLASHCODER Aug 31 '19 at 21:54
  • 1
    @BrowJr the changes proposed in [my QualityCentral ticket](https://web.archive.org/web/20171220121543/http://qc.embarcadero.com/wc/qcmain.aspx?d=12006) are made to `Forms.pas`. The changes proposed in [my CodeCentral submission](http://cc.embarcadero.com/Item/23574) are in the user's project code. – Remy Lebeau Sep 01 '19 at 00:55
  • @RemyLebeau, then the right is make these changes only on `Forms.pas`, Ok? – FLASHCODER Sep 01 '19 at 01:03
  • 1
    @BrowJr no, make changes in your own code when possible before resorting to changing Embarcadero's code. – Remy Lebeau Sep 01 '19 at 01:08
  • Long story short, backups. You NEVER want to go changing an original resource without first making a copy of it. You wouldn't experiment with some random alternative engine oil in the car you drive every day, would you? – Jerry Dodge Sep 01 '19 at 01:36
  • *`"make changes in your own code when possible before resorting to changing Embarcadero's code."`* i tried [**it**](https://web.archive.org/web/20171220121543/http://qc.embarcadero.com/wc/qcmain.aspx?d=12006), but comes several errors like for example: **`TCustomForm.CreateWindowHandle`** redeclared :-(. See [here](https://prnt.sc/p07dk3). – FLASHCODER Sep 01 '19 at 01:54
  • 5
    @BrowJr because [THAT QC CODE](https://web.archive.org/web/20171220121543/http://qc.embarcadero.com/wc/qcmain.aspx?d=12006) was meant to be changes for BORLAND to make to fix the issue at the VCL level. Changes for USERS to make in THEIR OWN CODE without altering the VCL is in [THIS CC CODE](http://cc.embarcadero.com/Item/23574) instead – Remy Lebeau Sep 01 '19 at 04:23
  • @RemyLebeau, thank you very much. Solved :-) I'm leaving the solution on **Edition** above. – FLASHCODER Sep 01 '19 at 19:09
  • @BrowJr your edit should have been posted as an answer instead, since it solves your issue. You are allowed to [post answers to your own questions](https://stackoverflow.com/help/self-answer). – Remy Lebeau Sep 01 '19 at 22:30

1 Answers1

1

After the help of comments above (mainly of @Remy Lebeau) follows this code working. I hope that can help someone ahead :-).

// MainForm
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  Unit2;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Application);
  Form2.Show;
end;

// MDIForm
type
  TForm2 = class(TForm)
    MainMenu1: TMainMenu;
    O1: TMenuItem;
    procedure O1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

uses
  Unit3;

{$R *.dfm}

procedure TForm2.O1Click(Sender: TObject);
begin
  Form3 := TForm3.Create(Self);
  Form3.Show;
end;

// MDIChild
type
  TForm3 = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    procedure CreateWindowHandle(const Params: TCreateParams); override;
    procedure DestroyWindowHandle; override;
  protected
    FMDIClientHandle: HWND;
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

uses
  Unit1;

{$R *.dfm}

procedure TForm3.CreateWindowHandle(const Params: TCreateParams);
var
  CreateStruct: TMDICreateStruct;

  function GetMDIClientHandle: HWND;
  begin
    Result := 0;
    if (Owner is TForm) then
      Result := TForm(Owner).ClientHandle;
    if (Result = 0) and (Application.MainForm <> nil) then
      Result := Application.MainForm.ClientHandle;
    if Result = 0 then
      raise EInvalidOperation.Create('No Parent MDI Form');
  end;

begin
  if (FormStyle = fsMDIChild) and not (csDesigning in ComponentState) then
  begin
    FMDIClientHandle := GetMDIClientHandle;
    with CreateStruct do
    begin
      szClass := Params.WinClassName;
      szTitle := Params.Caption;
      hOwner := HInstance;
      X := Params.X;
      Y := Params.Y;
      cX := Params.Width;
      cY := Params.Height;
      style := Params.Style;
      lParam := Longint(Params.Param);
    end;
    WindowHandle := SendMessage(FMDIClientHandle, WM_MDICREATE, 0, LongInt(@CreateStruct));
    Include(FFormState, fsCreatedMDIChild);
  end
  else
  begin
    FMDIClientHandle := 0;
    inherited CreateWindowHandle(Params);
    Exclude(FFormState, fsCreatedMDIChild);
  end;
end;

procedure TForm3.DestroyWindowHandle;
begin
  if fsCreatedMDIChild in FFormState then
    SendMessage(FMDIClientHandle, WM_MDIDESTROY, Handle, 0)
  else
    inherited DestroyWindowHandle;
  FMDIClientHandle := 0;
end;

procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := CaFree;
end;

enter image description here

FLASHCODER
  • 1
  • 7
  • 24