unit wMDIWindow0;

{ Feel free to use this unit as you want.
  First developped by Bernard Gisin
  This unit uses object programming to simplify the developpment
  of programs.

  Its purpose is to handle Multiple Interface Document windows (MDI)
----------------------------------}

// To tell FreePascal that the application is a Graphical User Interface
// i.e. is running in windows, not in text mode.
{$APPTYPE GUI}

INTERFACE
//"""""""

uses wWindow0, wMDIClientWindow0, wGlobals2, windows;

type
  PMDIWindow0 = ^TMDIWindow0;
  TMDIWindow0 = object(TWindow)
  //"""""""""""""""""""""""""""
//  hWin     : HWND;  // Handle on the edit box, got from TWindowBase
//  hParent : HWND;  // Handle on the parent, got from TWindowBase
//  poParent: PWindowBase0;  // Pointer on the parent, got from TWindowBase

//   hWinClient : HWND; defined in TWindow
  // handle on the Client Window of the main MDI window
  // It will be the parent of any MDI child window
  // object client window will come later.

  poWinClient : PMDIClientWindow;
  // Pointer on the MDI client object.

  nChildSubMenuPos : integer;
  // in which sub menu will the child window menu appair
  // 0 => appair in the first menu (File menu usually)
  // 1 => appair in the second menu (Edit menu)
  // usually set a number to have it in the 'Window' menu
  // this is usually set by the user

  nChildSubMenuID : integer;
  // When a child window is created, it will appair in the subMenu.
  // designated by 'nChildSubMenuPo'
  // When it is selected, it will send a WM_Command
  // with wPar = nChildSubMenuID     for the first child,
  // with wPar = nChildSubMenuID + 1 for the second child
  // with wPar = nChildSubMenuID + 2 for the Third child
  // etc.
  // with wPar = nChildSubMenuID + 8 for the ninth child
  // with wPar = nChildSubMenuID + 9 when a dialog with a list box is opened.
  // this is usually set by the user
  // set a number not used in the menu.

  fActivateObjectClientMessageHandler : boolean;
  // It is FALSE by default and maybe, will never be used.
  // Normally the Client message handler is not changed, but it can
  // change to activate the object client handler, to
  // have more control over the messages send to the client window.

  lPreviousAddressClient : longint;
  // Memorise the address of the previous window message handler
  // of the client window.
  // Used only if  fActivateObjectClientMessageHandler  is set TRUE.

  constructor Init(strWinTitlePrm:ShortString);
  // Call Init; at the beggining of a new Init constructor.
  // strWinNamePrm  = class name under which the window is registered
  // strWinTitle = title of the window

  destructor  Done; virtual;
  // Call Done; at the end of a new destructor.

  procedure WinCreate(strWinClass:ShortString); virtual;
  // creation of the window
  // Can be overriden, but not overriden usually
  // For the main window, it is automatically called in TApplication.Run
  // strWinClass = class name defining the window.
  // Put strWinClass = '' to use the one defined in the  Application object.
  // This is what is usually done.

  function ClientWinProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the window messages send to the client window
  // I Think it is useless, the client window doesn't receive
  // interesting messages.
  // by default it is not used, but can be activated
  // by seting  fActivateObjectClientMessageHandler:=TRUE
  // before creation of the window, typically in the init part, or
  // just after it.

  function WMNotify(wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the notification messages send from the richedit control
  // It is usually overriden, if used.

  function WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the menu messages
  // It is usually overriden

  function WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Process the messages comming to the MDI main window

  procedure WMSizeMoveFirst(wMsg:UINT; wPar:WPARAM; lPar:LPARAM); virtual;
  // The Window has been resized or moved, must take car of its child windows,
  // such as the tool bar, and a  RichText  control taking the whole
  // client area surface of its parent.

  function WindowProcFirst(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles messages for the library, before calling  WindowProc
  // It is usually not overriden
  end; // TMDIWindow0 = object(TWindow)
  TMDIWindow =  TMDIWindow0;
  PMDIWindow = ^TMDIWindow;

IMPLEMENTATION
//""""""""""""

uses wToolBar0, wMenus0, wControl0, {wParamApplic2,} wObjectCreatorLOW2,
     wErrors0, wDebug0;

var glnNotUsed : integer; // To avoid an error in the DevPascal 1.9 environment

Function ClientMDIWindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; stdcall; export;
//=======================================================================================================
// This is the message handle function, for the client window
// By default this is not used. It can by used
// by seting  fActivateObjectClientMessageHandler:=TRUE
// before creation of the window, typically in the init part, or
// just after it.
var
  // Pointer to the Main MDI window who owns the client window designated
  // by the handle  hWindow
  poMDIWin    : PMDIWindow0;

Begin
// Gets the adress of the object corresponding the MDIWindow
poMDIWin:=Pointer(GetWindowLong(hWindow, GWL_USERDATA));

// If we arrived here, the pointer is correct, since it has been modified
// in the same place where the client window procedure message handling
// has been changed. This could be verified knowing that
// poMDIWin^.hWinClient = hWindow always.
// Thus call the event handler of the object.
ClientMDIWindowProc:=poMDIWin^.ClientWinProc(hWindow, wMsg, wPar, lPar);
End;  // ClientMDIWindowProc

//***************************************************
// TMDIWindow0 = object(TWindow)
//***************************************************

constructor TMDIWindow0.Init(strWinTitlePrm:ShortString);
//=======================================================
begin
inherited Init(strWinTitlePrm);

// The first created window is supposed to be the main window.
// Keep a gloval variable pointer on the main window.
// if (gglpoMainWindow = NIL) then gglpoMainWindow:=@Self; done in the parent

if (wWindowType = GGLCTE_MAIN_WINDOW) then
   wWindowType :=GGLCTE_MAIN_MDI_WINDOW;

// Style of the window.
dwStyle:=ws_OverlappedWindow or WS_ClipChildren;

// must be set to zero, before it is defined in the CreateWindow calling the WM_Create message
hWinClient:=0;

// creates the object associated with the MDI Client
poWinClient:=PMDIClientWindow(gglpoObjCreate^.CreateMDIClientWindow(@Self));

// Will probably never change.
fActivateObjectClientMessageHandler:=FALSE;

// will will be defined at creation,
// if  fActivateObjectClientMessageHandler  set to TRUE
lPreviousAddressClient:=0;

// this should be set by the user.
// put by default 0, to have the children sub menu in the first menu
nChildSubMenuPos :=0;

// this should be set by the user.
// by default it is set to a number which is hoped not to be used in the menu
nChildSubMenuID:=5000;
end;  // TMDIWindow0.Init

destructor TMDIWindow0.Done;
//==========================
begin
dispose(poWinClient, Done);

inherited Done;
end;  // TMDIWindow0.Done

procedure TMDIWindow0.WinCreate(strWinClass:ShortString);
//=======================================================
var
  // to create the client part of an MDI main window.
  // It is the client part which controls the MDI child windows.
  clientcreate : TCLIENTCREATESTRUCT; // = CLIENTCREATESTRUCT in win32 SDK ref.

Begin
// This should no be called because  ShowWindow(hWin, SW_Shownormal);  is called at
// the end of the  inherited WinCreate;
// inherited WinCreate;

// Add a menu if wanted.
MenuCreate;

// Usually  strWinClass=''.
if (strWinClass = '') then strWinClass:=gglstrClassWinName;

strWinClass:=strWinClass+#0;
strWinTitle:=strWinTitle+#0;
hWin := CreateWindow ( @strWinClass[1], @strWinTitle[1],
                       dwStyle, nLeft, nTop, nWidth, nHeight,
                       hParent, hMenuWin, System.MainInstance, pDataCreation);

// store in the window structure, a signature characteristique of the library,
// an indication on the type of window object
// and a pointer on the corresponding window object.
// Thus from the object one get the handle through .hWin
// From the handle one get the pointer on the object through
// gglGetPointerObject(hWin:HWND; var wType:word; var poWin:PWindowBase);
// See wWindowBase.pp
SetWindowWord(hWin, 0, LOWORD(GGLCTE_SIGNATURE_WND_EXTRA));
SetWindowWord(hWin, 2, HIWORD(GGLCTE_SIGNATURE_WND_EXTRA));
SetWindowWord(hWin, 4, LOWORD(GGLCTE_SIGNATURE_WND_EXTRA));
SetWindowWord(hWin, 6, HIWORD(GGLCTE_SIGNATURE_WND_EXTRA));
SetWindowWord(hWin, 8, GGLCTE_MAIN_MDI_WINDOW);
SetWindowWord(hWin,10, 0);
SetWindowWord(hWin,12, LOWORD(Longint(@Self)));
SetWindowWord(hWin,14, HIWORD(Longint(@Self)));

// This must not be called here, but laster
// ShowWindow(hWin, SW_Shownormal);

// in which menu will the child window menu appair
// nChildSubMenuPos = 0 => appair in the File menu
// nChildSubMenuPos = 1 => appair in the Window menu
clientcreate.hWindowMenu  := GetSubMenu(hMenuWin, nChildSubMenuPos);

// When a child window is created, it will appair in the subMenu.
// designated by 'nChildSubMenuSub'
// When it is selected, it will send a WM_Command
// with wPar = nChildSubMenuID     for the first child,
// with wPar = nChildSubMenuID + 1 for the second child
// with wPar = nChildSubMenuID + 2 for the Third child
// etc.
// with wPar = nChildSubMenuID + 8 for the ninth child
// with wPar = nChildSubMenuID + 9 when a dialog with a list box is opened.
clientcreate.idFirstChild := nChildSubMenuID;

// Create the client window, containing the child windows.
// 'MDICLIENT' is a Windows predefined class
hWinClient := CreateWindow ('MDICLIENT', '',  // no title for the client
                            ws_Child or ws_Visible or ws_Group or ws_TabStop
                            or ws_ClipChildren or ws_HScroll or ws_VScroll,
                            0, 0, 0, 0, // no positionning
                            hWin, 1, MainInstance,
                            @clientcreate) ;

// Memorises the pointer on the object TMDIWindow0, in the
// control created by windows, in order to reuse it
SetWindowLong(hWinClient, GWL_USERDATA, longint(@Self));

// Sets data information concerning the MDI Client
poWinClient^.hWin:=hWinClient;
poWinClient^.hParent:=hWin;
// poWinClient^.poParent:=@Self; done already in the init part.
// poWinClient^.wWindowType:=GGLCTE_CLIENT_MDI_WINDOW;  // done in the init

if fActivateObjectClientMessageHandler then begin
   // Changes the function which handles the windows messages and
   // memorise the address of the previous function which handle the messages
   // If the return value is 0, there was an error and in this case,
   // the new handling function will never be called.
   lPreviousAddressClient:=SetWindowLong( hWinClient, GWL_WNDPROC,
                                          longint(@ClientMDIWindowProc));
   end;

// If the status line object has been created, then
// creates the status line window and add it to the Main MDI window.
if (poStatusLine <> NIL) and
   (poStatusLine^.poParent = @Self) and (poStatusLine^.hWin = 0) then begin
   // if a status line is wanted, create it automatically
   poStatusLine^.StatusCreate;
   end;

ShowWindow(hWin, SW_Shownormal);

// Registering the MDI child window class
//RegisterClass(WindowClassMDIChild); done in TApplication0.Run
End;  // TMDIWindow0.WinCreate

function TMDIWindow0.ClientWinProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//===============================================================================================
// Handles the window messages send to the client window
// I Think it is useless, the client window doesn't receive
// interesting messages.
// By default it is not used, but can be activated
// by seting  fActivateObjectClientMessageHandler:=TRUE
// before creation of the window, typically in the init part, or
// just after it.
begin
// Call the previous window proc of a control
if (lPreviousAddressClient = 0) then begin
   // error, not normal
   ErrorWrite( ERR_TMDIWindow0_ClientWinProc_1, 'in TMDIWindow0.ClientWinProc');
   ErrorComment(ERR_TMDIWindow0_ClientWinProc_1,
       'IMPOSSIBLE ! The address of the windows message handler');
   ErrorComment(ERR_TMDIWindow0_ClientWinProc_1,
       'of the TMDIWindow0 object has been lost.');
   ErrorComment(ERR_TMDIWindow0_ClientWinProc_1,
       'The program might crash, It''s a programming error!');

   // I don't know yet what to do with it.  ??????   DELETE  ???
   ClientWinProc := DefWindowProc(hWindow, wMsg, wPar, lPar);
//   ClientWinProc := DefFrameProc(hWin, hWinClient, wMsg, wPar, lPar);
   exit;
   end;

// Calls the default windows message handler of the client window
ClientWinProc:=CallWindowProc( WNDPROC(lPreviousAddressClient), hWindow,
                               wMsg, wPar, lPar);

{if (wMsg <> WM_MouseMove) and (wMsg <> WM_NCHitTest) and
   (wMsg <> WM_SetCursor) and (wMsg <> WM_GETTEXTLENGTH) and
   (wMsg <> WM_SetFocus) and (wMsg <> WM_KEYUP) and
   (wMsg <> WM_NCMOUSEMOVE) and (wMsg <> WM_KillFocus) then
   DBW0(1, DBMsgToStr(wMsg) + ITS(wPar) + ITS(lPar));  }
end;  // TMDIWindow0.ClientWinProc

function TMDIWindow0.WMNotify(wPar:WPARAM; lPar:LPARAM):LRESULT;
//==============================================================
// Handles the notification messages send from the richedit control
// It is usually overriden, if used.
var
  prNH        : ^NMHDR; // info associated with the notification message
  poCtrl      : PControl;

begin
// Notification message information. From whom and what.
prNH:=Pointer(lPar);

// The problem is that the handle doesn't identify always the control.
// only controls that has been defined in the library.
poCtrl:=Pointer(GetWindowLong(prNH^.hwndFrom, GWL_USERDATA));

// If the pointer is valid and represent the same handle, then
// it is a pointer on the object corresponding to the control.
if (not IsBadReadPtr(poCtrl, sizeOf(TControl0))) then begin
//   DBW0(2048, DBNotifToStr(prNH^.Code) + ITS(poCtrl^.hWin) + ' = ' + ITS(prNH^.hwndFrom));
   if (poCtrl^.hWin = prNH^.hwndFrom) then begin
      // the control has been identified to be the one having the right handle
      // Calls the notification message to the control's notification message handler
      // poCtrl^.Code = notification message, as NM_XXX and EN_XXX and ...
      poCtrl^.CtrlNotifMessageHandle(prNH^.Code, lPar);
      end;
   end;

WMNotify := DefFrameProc(hWin, hWinClient, WM_NOTIFY, wPar, lPar);
end;  //TMDIWindow0.WMNotify

function TMDIWindow0.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//===============================================================
// Handles the menu messages
var
  poCtrl      : PControl;
  wNoticode   : word;
  hWinChild   : HWND; // handle of the active MDI child window

begin
// if it is different from 0 and 1, it is a notification message send
// from the child control to its parent.
// send it back to the object control

if (lPar <> 0) then begin
   // It is a notification message send from the child control to its parent.
   // send it back to the object control
   wNotiCode := HiWord(wPar);

   // this message is a notification code from the control.
   // lPar = handle of the control, get the pointer on the object.
   poCtrl:=Pointer(GetWindowLong(lPar, GWL_USERDATA));

  // If the pointer is valid and represent the same handle, then
  // it is a pointer on the object corresponding to the control.
  if (not IsBadReadPtr(poCtrl, sizeOf(TControl0))) then begin
//      DBW0(4096, DBNotifToStr(wNotiCode) + ITS(poCtrl^.hWin) + ' = ' + ITS(lPar));
      if (poCtrl^.hWin = lPar) then begin
         // The control has been identified to be the one having the right handle
         // Calls the notification message to the control's notification
         // message handler
         // poCtrl^.Code = notification message, as NM_XXX and EN_XXX and ...
         poCtrl^.CtrlNotifMessageHandle(wNotiCode, lPar);
         end;
      end;
   end;

if (lPar = 0) then begin
   // Here comes the standard menu messages handling.
   // The library will handle many messages automatically.
   WMCommand :=0;  // default value if message is handeled

   case LoWord(wPar) of
      // standard menu message to close the window.
      //""""""""""""""""""""""""""""""""""""""""""""
      // Closes the MDI child window.
      65400 : begin
         hWinChild:=LOWORD (SendMessage (hWinClient, WM_MDIGETACTIVE, 0, 0)) ;

         if (SendMessage ( hWinChild, WM_QUERYENDSESSION, 0, 0) <> 0) then
            SendMessage (hWinClient, WM_MDIDESTROY, hWinChild, 0);
         end; // 65400

      // Messages for arranging windows
      65401 : SendMessage (hWinClient, WM_MDITILE, 0, 0);
      65402 : SendMessage (hWinClient, WM_MDICASCADE, 0, 0);
      65403 : SendMessage (hWinClient, WM_MDIICONARRANGE, 0, 0);

      // If it is the main window, this will also quit the application.
      65500 : PostMessage( hWin,WM_Close,0,0);

      65501 : DBW0(0, '');  // just open the debugging window, if it's not already done.

      else WMCommand := DefFrameProc(hWin, hWinClient, WM_COMMAND, wPar, lPar);
      end; // case LoWord(wPar) of

   exit;
   end;  // if (lPar = 0) then begin

WMCommand := DefFrameProc(hWin, hWinClient, WM_COMMAND, wPar, lPar);
end;  // TMDIWindow0.WMCommand

function TMDIWindow0.WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//=========================================================================================
// Process the messages comming to the MDI main window
const
  strMemStatusLine : ShortString = '';
  // when entering the menu, memorised what was in the status line.
  // Must be const to hold its value when we quit and re-enter the procedure.
  // Could be a globale variable too
var
  // Information stored in the Hash table created with the menu
  prML        : PRMenuLine;
  wInfoL      : word32;  // not used here, but must be passed as a parameter
  strS        : string[200]; // just to test if the child window is maximized.
  nLen        : integer;

Begin
WindowProc := 0; // Default return value when processing a message

{if (wMsg <> WM_MouseMove)   and (wMsg <> WM_NCMouseMove) and
   (wMsg <> WM_MENUSELECT )   and (wMsg <> WM_ENTERIDLE ) and
   (wMsg <> WM_SetCursor)   and (wMsg <> WM_NCHittest) and
//   (wMsg <> WM_SetFocus) and (wMsg <> WM_KillFocus) and
//   (wMsg <> WM_KEYDOWN) and (wMsg <> WM_KEYUP) and
   (wMsg <> WM_Move)        and (wMsg <> WM_NCActivate) then
   DBW0(32, DBMsgToStr(wMsg) + ITS(wPar) + ITS(lPar)); }

Case wMsg Of
   WM_Destroy : PostQuitMessage (0); // quit the application
   WM_Notify  : WindowProc:=WMNotify(wPar, lPar);
   WM_Command : WindowProc:=WMCommand(wPar, lPar);
   WM_Move,
   WM_Size : if (poStatusLine <> NIL) then begin
                exit; // do not call the DefFrameProc.
                      // If you do, the status line height would not
                      // be taken into account of the client height.
                end
             else WindowProc :=DefFrameProc(hWindow, hWinClient, wMsg, wPar, lPar);

   WM_MENUSELECT : if (poStatusLine <> NIL) and (poMenu <> NIL) then begin
//      DBW0(32, DBMsgToStr(wMsg) + ITS(LoWord(wPar)) + ITS(HiWord(wPar)) + ITS(lPar));
      // display an info in the status line.

      if ((HiWord(wPar) and MF_POPUP) = MF_POPUP) then begin
         // In MDI windows, the position of a popup menu changes it its
         // child window is maximized.
         // thus, test if the first menu has a name. If not, the
         // child window is maximized, and a shift must be done
         // to retreive the right info of the menu
         nLen:=GetMenuString(lPar, 0, @strS[1], 200, MF_BYPOSITION);

         if (nLen = 0) then nLen:=LoWord(wPar)-1 // must shift
         else               nLen:=LoWord(wPar);

         if (nLen < 0) then begin
            // we are on the child system menu.
            prML:=NIL;
            poStatusLine^.SetStatusText(0, ''); // empty the status line
            end
         else prML:=poMenu^.oHt.GetPointerW2(lPar, word32(65536)*word32(nLen), wInfoL)
         end
      else prML:=poMenu^.oHt.GetPointerW2(lPar, LoWord(wPar), wInfoL);

      if (prML <> NIL) then poStatusLine^.SetStatusText(0, prML^.strInfo);
                            // display the info in the status line
      end; // WM_MENUSELECT : begin

   WM_ENTERMENULOOP : if (poStatusLine <> NIL) and (poMenu <> NIL) then
                         strMemStatusLine:=poStatusLine^.GetStatusText(0);
                         // Before changing the status line, memorise what was in it.
   WM_EXITMENULOOP  : if (poStatusLine <> NIL) and (poMenu <> NIL) then
                         poStatusLine^.SetStatusText(0, strMemStatusLine);
                         // set back what was in the status line.
   else begin // Case wMsg Of
      // Default processing of the messages, for MDI windows
      WindowProc :=DefFrameProc(hWindow, hWinClient, wMsg, wPar, lPar);
      end; // else Case wMsg Of
   End; // Case wMsg Of
End;  // TMDIWindow0.WindowProc

procedure TMDIWindow0.WMSizeMoveFirst(wMsg:UINT; wPar:WPARAM; lPar:LPARAM);
//=========================================================================
// The Window has been resized, must take car of its child windows,
// such as the tool bar, and a  RichText  control taking the whole
// client area surface of its parent.
var
  rRec        : RECT;
  wChild      : word; // to loop over all its children
  poTBar      : PToolBar;
  nSizeTopL,  // size on the top, taken by a toolbar
  nSizeLeftL  // size on the left, taken by a toolbar
              : int32;

begin
if not IsWindowVisible(hWin) then exit;

// Memorise its size state, position and size
if      (wPar = SIZE_MAXIMIZED) then wSizeState:=SIZE_MAXIMIZED
else if (wPar = SIZE_MINIMIZED) then wSizeState:=SIZE_MINIMIZED
else if (wPar = SIZE_RESTORED)  then begin
   wSizeState:=SIZE_RESTORED;

   if not (IsZoomed(hWin) or IsIconic(hWin)) then begin
      // Remember the position and size of the window
      GetWindowRect(hWin, @rRec);
      nLeft  :=rRec.Left;
      nTop   :=rRec.Top;
      nWidth :=rRec.Right  - rRec.Left;
      nHeight:=rRec.Bottom - rRec.Top;
      end;
   end; // else if (wPar = SIZE_RESTORED)  then begin

// Memorise the client size.
GetClientRect(hWin, @rRec);
nClientWidth  :=rRec.Right;
nClientHeight :=rRec.Bottom;

// Sizes take from the client window by the toolbar
nSizeTopL  :=0;
nSizeLeftL :=0;

// Loop over all its children, to see if they have to move or to be resized.
if (papoChild <> NIL) then for wChild :=1 to nNumberOfChild do begin
   if (papoChild^[wChild]^.wWindowType = GGLCTE_ToolBar) then begin
      poTBar :=PToolBar(papoChild^[wChild]);

      if (poTBar^.wTBPosition = 1) then begin
         // Horizontal toolbar on the top
         nSizeTopL:=nSizeTopL + poTBar^.nYSizePix;
         end;

      if (poTBar^.wTBPosition = 16) then begin
         // Left vertical. Must shorten if a status line take place in the bottom
         nSizeLeftL:=nSizeLeftL + poTBar^.nXSizePix;

         if (poStatusLine <> NIL) then begin
            MoveWindow ( poTBar^.hWin,0, 0, poTBar^.nXSizePix,
                         nClientHeight - int32(poStatusLine^.wHeight), TRUE);
            end;
         end;
      // else other cases are not treated yet.
      end; // if (papoChild^[wChild]^.wWindowType = GGLCTE_ToolBar ...
   end; // for wChild :=1 to nNumberOfChild do begin

if (wMsg = WM_Size) then begin
   // send the message to all childrens
   //  WMToAllChildren(hWin, wMsg, wPar, lPar); the main MDI window has should not do it

   if (poStatusLine <> NIL) then begin
      poStatusLine^.WMFromParent(hWin, wMsg, wPar, lPar);
      GetClientRect(hWin, @rRec);

      // Must change the size of the client window too
      MoveWindow ( hWinClient,nSizeLeftL, nSizeTopL, rRec.Right - nSizeLeftL,
                   rRec.Bottom - int32(poStatusLine^.wHeight) - nSizeTopL, True);
      end;
   end; // if (wMsg = WM_Size) then begin
end;  // TMDIWindow0.WMSizeMoveFirst

function TMDIWindow0.WindowProcFirst(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//===========================================================================================
// Handles messages for the library, before calling  WindowProc
var
  poWin       : PMDIWindow0;

begin
Case wMsg Of
   WM_Move,
   WM_Size : WMSizeMoveFirst(wMsg, wPar, lPar);
   end; // Case wMsg Of

// call the window message processing
WindowProcFirst:=WindowProc(hWindow, wMsg, wPar, lPar);

if (wMsg = WM_NCDestroy) then begin
   // The window has been destroyed, do not destroy it again
   WindowDestroyAllChild; // destroy all childs, if not already done.
   hWin:=0;

   if (wIsDone = 1) and (@Self <> gglpoMainWindow) then begin
      // dispose also the object
      // The main window will be disposed in the application's destructor
      poWin :=@Self;
      dispose(poWin, Done);
      end;
   // else it has already been disposed.
   end;

end;  // TMDIWindow0.WindowProcFirst

end.  // unit wMDIWindow0;

