UNIT PMObject;

{***************************************************************************
*                                                                          *
*                                                                          *
*                Speed-386 PASCAL for OS/2 Version 1.0                     *
*           (C) 1993,94 R. Nrnberger All rights reserved !                *
*                                                                          *
*                                                                          *
* This file    : Basic fuctionality of ObjectPM library V1.0               *
* Last updated : 13.9.1994                                                 *
*                                                                          *
****************************************************************************}

INTERFACE

USES PmTypes;

{General objects}

TYPE
    TYPE TMessage=RECORD
                       Win:HWND;
                       Message:LONGWORD;
                       Para1,Para2:LONGWORD;
                       Handled:BOOLEAN;
                       Result:LONGWORD;
                  END;

    TWindow=OBJECT
         Title:STRING;                 {Title of window}
         FontName:STRING;              {Name of default output font}
         FontWidth:BYTE;               {Width of default output font}
         FontHeight:BYTE;              {Height of default output font}
         ForeColor:LONGINT;            {Default output color}
         BackColor:LONGINT;            {Default window background color}
         WindowID:LONGWORD;            {ID of window for external resources}
         ClientHandle:HWND;            {Client (output area) handle of window}
         FrameHandle:HWND;             {Frame handle of window}
         DesktopClientHandle:HWND;     {Desktop (output area) handle}
         DesktopFrameHandle:HWND;      {Desktop frame handle}
         {*****************************************************}
         {Do not change this location because its hard coded}
         FUNCTION HandleEvent(Win:HWND;Msg:LONGWORD;
                              para1,para2:POINTER;
                              VAR Handled:BOOLEAN):LONGWORD;VIRTUAL;
         {**************************************************}
         {Do not change this location because its hard coded}
         FUNCTION MDIHandleEvent(Win:HWND;Msg:LONGWORD;
                                 para1,para2:POINTER;
                                 VAR Handled:BOOLEAN;Data:POINTER):LONGWORD;VIRTUAL;
         {**************************************************}
         {Do not change this location because its hard coded}
         FUNCTION DesktopHandleEvent(Win:HWND;Msg:LONGWORD;
                                     para1,para2:POINTER;
                                     VAR Handled:BOOLEAN):LONGWORD;VIRTUAL;
         {**************************************************}
         CONSTRUCTOR Init;
         DESTRUCTOR Done;
         PROCEDURE DeleteData;VIRTUAL;
         PROCEDURE CreateWindow(Parent:HWND;Style,CreateFlags:LONGWORD;
                                Class,Title:String;StyleClient:LONGWORD;
                                Res,id:LONGWORD);VIRTUAL;
         PROCEDURE Redraw(rc:RECTL;_hps:HPS;Win:HWND);VIRTUAL;
         PROCEDURE WMClose(VAR Msg:TMessage);VIRTUAL WM_CLOSE;
         PROCEDURE WMCreate(VAR Msg:TMessage);VIRTUAL WM_CREATE;
         PROCEDURE WMActivate(VAR Msg:TMessage);VIRTUAL WM_ACTIVATE;
         PROCEDURE WMMouseMove(Win:HWND;x,y:INTEGER);VIRTUAL;
         PROCEDURE WMButton1Click(Win:HWND;x,y:INTEGER);VIRTUAL;
         PROCEDURE WMButton1DoubleClick(Win:HWND;x,y:INTEGER);VIRTUAL;
         PROCEDURE WMButton1Up(Win:HWND;x,y:INTEGER);VIRTUAL;
         PROCEDURE WMButton1Down(Win:HWND;x,y:INTEGER);VIRTUAL;
         PROCEDURE WMButton2Click(Win:HWND;x,y:INTEGER);VIRTUAL;
         PROCEDURE WMButton2Up(Win:HWND;x,y:INTEGER);VIRTUAL;
         PROCEDURE WMButton2Down(Win:HWND;x,y:INTEGER);VIRTUAL;
         PROCEDURE WMEraseBackGround(Win:HWND;rc:RECTL;_hps:HPS);VIRTUAL;
         PROCEDURE WMDestroy(VAR Msg:TMessage);VIRTUAL WM_DESTROY;
         PROCEDURE WMSize(VAR Msg:TMessage);VIRTUAL WM_SIZE;

         PROCEDURE SetColors(Col,BackCol:LONGINT);VIRTUAL;
         PROCEDURE HandleScanEvent(Win:HWND;scan:WORD);VIRTUAL;
         PROCEDURE HandleCharEvent(Win:HWND;Ch:CHAR);VIRTUAL;
         PROCEDURE HandleCommand(Win:HWND;command:WORD);VIRTUAL;
         PROCEDURE InvalidateAppWindow;VIRTUAL;
         PROCEDURE GetMaxDesktopWindow(VAR _swp:SWP);VIRTUAL;
         PROCEDURE GetPS(VAR ps:HPS);VIRTUAL;
         PROCEDURE ReleasePS(ps:HPS);VIRTUAL;
         PROCEDURE PrintString(ps:HPS;s:STRING;x,y:LONGINT);VIRTUAL;
         PROCEDURE SetWindowTitle(s:STRING);VIRTUAL;
    END;

    TApplication=OBJECT(TWindow)
         ToolBarSize:WORD;
         StatusBarSize:WORD;
         LeftToolBarSize:WORD;
         RightToolBarSize:WORD;
         ToolBarInterior:PToolBarInterior;
         StatusBarInterior:PStatusBarInterior;
         MenuHelpItems:PMenuHelpItems;
         HasIcon:BOOLEAN;              {TRUE if window has icon}
         HasMenu:BOOLEAN;              {TRUE if window has menu}
         HasAccel:BOOLEAN;             {TRUE if window has accel table}
         HasHelp:BOOLEAN;              {TRUE if window has help window}
         HelpFileName:String;          {Name of associated help file}
         HelpTitle:STRING;             {Title of associated help file}
         HelpWindow:HWND;              {Window id of help window}
         WinCX,WinCY:LONGWORD;         {Window size on create}
         WinX,WinY:LONGWORD;           {Window position on create}
         FUNCTION HandleEvent(Win:HWND;Msg:LONGWORD;
                              para1,para2:POINTER;
                              VAR Handled:BOOLEAN):LONGWORD:VIRTUAL;
         FUNCTION DesktopHandleEvent(Win:HWND;Msg:LONGWORD;
                                     para1,para2:POINTER;
                                     VAR Handled:BOOLEAN):LONGWORD:VIRTUAL;
         CONSTRUCTOR Init;
         DESTRUCTOR Done;
         PROCEDURE Redraw(rc:RECTL;_hps:HPS;Win:HWND):VIRTUAL;
         PROCEDURE Run(Id:LONGWORD;Title:String;Col,bcol:LONGINT);VIRTUAL;
         PROCEDURE StatusBarSetText(id:WORD;item:STRING;
                                    Col:LONGWORD);VIRTUAL;
         PROCEDURE DesktopRedraw(rc:RECTL;_hps:HPS;Win:HWND);VIRTUAL;
         PROCEDURE GetMaxAppWindow(VAR _swp:SWP);VIRTUAL;
         PROCEDURE InsertHelp(Filename,WindowTitle:String);VIRTUAL;
         PROCEDURE RedrawToolBar(rc:RECTL;_hps:HPS);VIRTUAL;
         PROCEDURE RedrawLeftToolBar(rc:RECTL;_hps:HPS);VIRTUAL;
         PROCEDURE RedrawRightToolBar(rc:RECTL;_hps:HPS);VIRTUAL;
         PROCEDURE RedrawStatusBar(rc:RECTL;_hps:HPS);VIRTUAL;
         PROCEDURE InsertResources(Menu,Accel,Icon:BOOLEAN);VIRTUAL;
         PROCEDURE CreateToolBar(Size:WORD);VIRTUAL;
         PROCEDURE CreateLeftToolBar(Size:WORD);VIRTUAL;
         PROCEDURE CreateRightToolBar(Size:WORD);VIRTUAL;
         PROCEDURE CreateStatusBar(Size:WORD);VIRTUAL;
         PROCEDURE StatusBarInsertItem(id:WORD;x,y,cx,cy:LONGWORD);VIRTUAL;
         PROCEDURE SetMenuState(id:WORD;State:BOOLEAN);VIRTUAL;
         PROCEDURE ToolBarInsertButton(id,res,x,y,cx,cy:LONGWORD);VIRTUAL;
         PROCEDURE ToolBarInsertControl(id,x,y,cx,cy,flag,class:LONGWORD;
                                        title:STRING);VIRTUAL;
         PROCEDURE InsertMenuHelp(StatusID,MenuID:WORD;
                                  HelpText:String;Col:LONGWORD);VIRTUAL;
         PROCEDURE AppCreateNotify(AppFrWin,AppWin:HWND);VIRTUAL;
         PROCEDURE SetupMenu(Frame,Client:HWND);VIRTUAL;
         PROCEDURE AppRunNotify(AppFrWin:HWND);VIRTUAL;
         PROCEDURE HandleCommand(Win:HWND;command:WORD):VIRTUAL;
         PROCEDURE DisplayHelp(PanelID:WORD);VIRTUAL;
         PROCEDURE PopupMenu(VAR Menu:HWND;id:LONGWORD;
                             x,y:LONGWORD;Parent:HWND);VIRTUAL;
         PROCEDURE WMMenuSelect(Win:HWND;para1:POINTER);VIRTUAL;
         PROCEDURE DesktopEraseBackGround(Win:HWND;rc:RECTL;_hps:HPS);VIRTUAL;
         PROCEDURE WMSize(VAR Msg:TMessage):VIRTUAL WM_SIZE;
         PROCEDURE WMClose(VAR Msg:TMessage):VIRTUAL WM_CLOSE;
    END;

    TMDIApplication=OBJECT(TApplication)
         ChildCount:BYTE;
         ActiveChild:HWND;
         MinimizedCount:BYTE;
         CONSTRUCTOR Init;
         DESTRUCTOR Done;
         PROCEDURE WMClose(VAR Msg:TMessage):VIRTUAL WM_CLOSE;
         PROCEDURE TileWindows;VIRTUAL;
         PROCEDURE CascadeWindows;VIRTUAL;
         PROCEDURE NextWindow;VIRTUAL;
         PROCEDURE CloseAllWindows;VIRTUAL;
         PROCEDURE HandleCommand(Win:HWND;command:WORD):VIRTUAL;
         PROCEDURE AppRunNotify(AppFrWin:HWND):VIRTUAL;
         PROCEDURE MDINoMoreChilds;VIRTUAL;
         PROCEDURE MDIWMSize(Win:HWND;Data:POINTER);VIRTUAL;
         FUNCTION HandleEvent(Win:HWND;Msg:LONGWORD;
                              para1,para2:POINTER;
                              VAR Handled:BOOLEAN):LONGWORD:VIRTUAL;
         FUNCTION CreateMDIChild(resid:LONGWORD;Title:string;
                                 Extra:POINTER;fcfFlags:LONGWORD;
                                 Col,BCol:LONGINT):HWND;VIRTUAL;
         FUNCTION MDIHandleEvent(Win:HWND;Msg:LONGWORD;
                                 para1,para2:POINTER;
                                 VAR Handled:BOOLEAN;
                                 Data:POINTER):LONGWORD:VIRTUAL;
         PROCEDURE MDIRedraw(rc:RECTL;_hps:HPS;Win:HWND;Data:POINTER);VIRTUAL;
         FUNCTION GetMDIColor(Win:HWND):LONGINT;VIRTUAL;
         FUNCTION GetMDIBackColor(Win:HWND):LONGINT;VIRTUAL;
         PROCEDURE SetMDIColor(Win:HWND;col:LONGINT);VIRTUAL;
         PROCEDURE SetMDIBackColor(Win:HWND;bcol:LONGINT);VIRTUAL;
         PROCEDURE MDICreateNotify(MDIFrWin,MDIWin:HWND;Data:POINTER);VIRTUAL;
         PROCEDURE WMMDIClose(Win:HWND;Data:POINTER);VIRTUAL;
         PROCEDURE MDIHandleCommand(Win:HWND;command:WORD;Data:POINTER);VIRTUAL;
         PROCEDURE MDIHandleScanEvent(Win:HWND;scan:WORD;Data:POINTER);VIRTUAL;
         PROCEDURE MDIHandleCharEvent(Win:HWND;Ch:CHAR;Data:POINTER);VIRTUAL;
         FUNCTION MDIGetDataPointer(Win:HWND):POINTER;VIRTUAL;
         FUNCTION MDIGetTopWindow(VAR Extra:POINTER):HWND;VIRTUAL;
         PROCEDURE MDIBringToTop(Win:HWND);VIRTUAL;
         PROCEDURE MDIWMMouseMove(Win:HWND;x,y:INTEGER;Data:POINTER);VIRTUAL;
         PROCEDURE MDIWMButton1Click(Win:HWND;x,y:INTEGER;Data:POINTER);VIRTUAL;
         PROCEDURE MDIWMButton1DoubleClick(Win:HWND;x,y:INTEGER;Data:POINTER);VIRTUAL;
         PROCEDURE MDIWMButton1Down(Win:HWND;x,y:INTEGER;Data:POINTER);VIRTUAL;
         PROCEDURE MDIWMEraseBackGround(Win:HWND;rc:RECTL;_hps:HPS);VIRTUAL;
         PROCEDURE MDIWMButton1Up(Win:HWND;x,y:INTEGER;Data:POINTER);VIRTUAL;
         PROCEDURE InvalidateMDIWindow(Win:HWND);VIRTUAL;
         PROCEDURE WMSize(VAR Msg:TMessage):VIRTUAL WM_SIZE;
    END;

FUNCTION PointerToWord(p:POINTER):WORD;
PROCEDURE MessageBox(msg:String);
PROCEDURE ErrorBox(Options:LONGWORD;err:String);
FUNCTION ConfirmBox(Options:LONGWORD;msg:String):BOOLEAN;
PROCEDURE MaximizeWindow(Win:HWND);
PROCEDURE MinimizeWindow(Win:HWND);
PROCEDURE HideWindow(Win:HWND);
PROCEDURE ShowWindow(Win:HWND);
PROCEDURE DisableWindow(Win:HWND);
PROCEDURE EnableWindow(Win:HWND);
PROCEDURE RestoreWindow(Win:HWND);
FUNCTION IsWindowMaximized(Win:HWND):BOOLEAN;
FUNCTION IsWindowMinimized(Win:HWND):BOOLEAN;
PROCEDURE DrawStringXY(_hps:HPS;VAR pt:POINTL;VAR s:string;start,Len:LONGWORD;
                       Color,BackColor:LONGWORD);
PROCEDURE InvalidateWindow(Win:HWND);
PROCEDURE WindowToTop(FrameWin:HWND);
PROCEDURE SetWindowPos(Win:HWND;x,y,cx,cy:LONGINT);
PROCEDURE GetWindowPos(Win:HWND;VAR x,y,cx,cy:LONGINT);


VAR
   AppWinHandle,AppWinFrameHandle:HWND;
   ChildIconRes:LONGWORD;
   DragWindow:HWND;
   LastDragPos:POINTER;
   MouseButton1Down:BOOLEAN;
   Drag_Mode:BOOLEAN;

IMPLEMENTATION

VAR {Private}
   InCtrlK:BOOLEAN;
   TWindowClass:String[40];          {Standard class for TWindow}
   TDesktopWindowClass:STRING[40];   {Desktop window class}
   TMDIWindowClass:STRING[40];       {MDI window}

CONST {private}

      CLR_FALSE                =-5;
      CLR_TRUE                 =-4;
      CLR_ERROR                =-255;
      CLR_DEFAULT              =-3;
      CLR_WHITE                =-2;
      CLR_BLACK                =-1;
      CLR_BACKGROUND           = 0;
      CLR_BLUE                 = 1;
      CLR_RED                  = 2;
      CLR_PINK                 = 3;
      CLR_GREEN                = 4;
      CLR_CYAN                 = 5;
      CLR_YELLOW               = 6;
      CLR_NEUTRAL              = 7;
      CLR_DARKGRAY             = 8;
      CLR_DARKBLUE             = 9;
      CLR_DARKRED              = 10;
      CLR_DARKPINK             = 11;
      CLR_DARKGREEN            = 12;
      CLR_DARKCYAN             = 13;
      CLR_BROWN                = 14;
      CLR_PALEGRAY             = 15;

IMPORTS

       FUNCTION WinCreateStdWindow(hwndParent:HWND;flStyle:LONGWORD;
                                   VAR pflCreateFlags:LONGWORD;
                                   pszClientClass:PSZ;
                                   pszTitle:PSZ;
                                   styleClient:LONGWORD;
                                   hmod:HMODULE;
                                   idResources:LONGWORD;
                                   VAR Client:HWND):LONGWORD;
                    APIENTRY;             PMWIN index 908;
       FUNCTION WinRegisterClass(ahab:LONGWORD;pszClassName:PSZ;
                                 pfnWndProc:POINTER;flStyle:LONGWORD;
                                 cbWindowData:LONGWORD):LONGWORD;
                    APIENTRY;             PMWIN index 926;
        FUNCTION WinSetWindowULong(ul:LONGWORD;
                                   _index:LONGWORD;
                                   _hwnd:HWND):LONGWORD:         PMWIN index 878;
        FUNCTION WinSetWindowPos(fl:LONGWORD;
                                 cy,cx,y,x:LONGWORD;
                                 hwndInsertBehind:HWND;
                                 _hwnd:HWND):LONGWORD:           PMWIN index 875;
        FUNCTION WinBeginPaint(VAR prclPaint:RECTL;
                               _hps:HPS;_hwnd:HWND):
                               LONGWORD:                         PMWIN index 703;
        FUNCTION WinEndPaint(_hps:HPS):LONGWORD:                 PMWIN index 738;
        FUNCTION WinQueryWindowRect(VAR prclDest:RECTL;
                                    _hwnd:HWND ):
                                    LONGWORD:                    PMWIN index 840;
        FUNCTION WinFillRect(lColor:LONGWORD;
                             VAR prcl:RECTL;
                             _hps:HPS):LONGWORD:                 PMWIN index 743;
        PROCEDURE WinSubClassWindow(Proc:POINTER;Win:HWND):      PMWIN index 929;
        PROCEDURE WinInvalidateRect(c:LONGWORD;r:POINTER;
                                    Win:HWND):                   PMWIN index 765;
        FUNCTION WinDestroyWindow(_hwnd:HWND):
                                  LONGWORD:                      PMWIN index 728;
        FUNCTION WinQueryWindow(cmd:LONGWORD;
                                _hwnd:HWND):LONGWORD:            PMWIN index 834;
        FUNCTION WinPostMsg(mp2,mp1:POINTER;
                            msg:LONGWORD;
                            _hwnd:HWND):LONGWORD:                PMWIN index 919;
        FUNCTION WinSendMsg(MPARAM2,MPARAM1:POINTER;
                            msg:LONGWORD;
                            _hwnd:HWND):POINTER:                 PMWIN index 920;
        FUNCTION GpiSetColor(lColor:LONGWORD;
                             _hps:HPS):LONGINT:                  PMGPI index 517;
        FUNCTION GpiSetBackColor(lColor:LONGINT;
                                 _hps:HPS):LONGWORD:             PMGPI index 504;
        FUNCTION GpiSetBackMix(lMixMode:LONGINT;
                               _hps:HPS):LONGWORD:               PMGPI index 505;
        FUNCTION GpiCharStringAt(VAR pchString;
                                 lCount:LONGWORD;
                                 VAR pptlPoint:POINTL;
                                 _hps:HPS):LONGWORD:             PMGPI index 359;
        FUNCTION GpiMove(VAR Point:POINTL;hp:HPS):LONGWORD:
                                                                 PMGPI index 404;
        FUNCTION GpiBox(VRound,HRound:LONGWORD;VAR Point:POINTL;
                       Control:LONGWORD;hp:HPS):LONGWORD:        PMGPI index 356;
        FUNCTION WinQueryWindowUShort(_index:LONGWORD;
                                        _hwnd:HWND):WORD:        PMWIN index 844;
        FUNCTION WinQueryWindowULong(_index:LONGWORD;
                                     _hwnd:HWND):
                                     LONGWORD:                   PMWIN index 843;
        FUNCTION WinEnableWindow(fEnable:LONGWORD;
                                 _hwnd:HWND):LONGWORD:           PMWIN index 735;
        FUNCTION WinMessageBox(flStyle:LONGWORD;
                               idWindow:LONGWORD;
                               pszCaption:PSZ;
                               pszText:PSZ;
                               hwndOwner:HWND;
                               hwndParent:HWND):LONGWORD:        PMWIN index 789;
        FUNCTION WinSetWindowText(psztext:PSZ;
                                  _hwnd:HWND):LONGWORD:          PMWIN index 877;
        FUNCTION WinCreateHelpInstance(VAR HInit:THelpInit;
                                       hab:LONGWORD):
                                       LONGWORD:                 HELPMGR index 51;
        FUNCTION WinDestroyHelpInstance(hwndHelp:HWND):
                                        LONGWORD:                HELPMGR index 52;
        FUNCTION WinAssociateHelpInstance(Frame,Help:HWND):
                                          LONGWORD:              HELPMGR index 54;
        FUNCTION WinQuerySysValue(iSysValue:LONGWORD;
                                  hwndDesktop:HWND):
                                  LONGWORD:                      PMWIN index 829;
        FUNCTION WinDrawBorder(flCmd,clrBack,ClrFore,cy,cx:LONGWORD;
                               VAR rec:RECTL;hp:HPS):LONGWORD:   PMWIN index 731;
        PROCEDURE WinReleasePS(_hps:HPS):                        PMWIN index 848;
        FUNCTION  WinGetPS(Win:HWND):HPS:                        PMWIN index 757;
        FUNCTION WinWindowFromID(id:LONGWORD;
                                 hwndParent:HWND):HWND:          PMWIN index 899;
        FUNCTION WinCreateWindow(pPresParams:POINTER;
                                 pCtlData:POINTER;
                                 id:LONGWORD;
                                 hwndInsertBehind:HWND;
                                 hwndOwner:HWND;
                                 cy,cx,y,x:LONGWORD;
                                 flStyle:LONGWORD;
                                 pszName:PSZ;
                                 Class:LONGWORD;
                                 hwndParent:HWND):HWND:          PMWIN index 909;
        FUNCTION WinQueryWindowPos(_swp:SWP;
                                   _hwnd:HWND):LONGWORD:         PMWIN index 837;
        FUNCTION WinSetMultWindowPos(cswp:LONGWORD;
                                     VAR pswp:SWP;
                                     _hab:LONGWORD):
                                     LONGWORD:                   PMWIN index 863;
        FUNCTION WinBeginEnumWindows(_hwnd:HWND):
                                     LONGWORD:                   PMWIN index 702;
        FUNCTION WinGetNextWindow(_henum:LONGWORD):HWND:         PMWIN index 756;
        FUNCTION WinEndEnumWindows(_henum:LONGWORD):
                                   LONGWORD:                     PMWIN index 737;
        FUNCTION WinSetWindowUShort(us:LONGINT;
                                    _index:LONGWORD;
                                    _hwnd:HWND):LONGWORD:        PMWIN index 879;
        FUNCTION WinSetOwner(hwndNewOwner,_hwnd:HWND):
                             LONGWORD:                           PMWIN index 864;
        FUNCTION WinLoadMenu(id,res:LONGWORD;
                             Owner:HWND):HWND:                   PMWIN index 778;
        FUNCTION WinPopupMenu(fsOptions,idItem,ly,lx:LONGWORD;
                              Menu,Owner,Parent:HWND):LONGWORD:  PMWIN index 937;
END;

{*************************************************************************
*                                                                        *
*   Common Procedures and functions                                      *
*                                                                        *
**************************************************************************}



PROCEDURE StartHandler(para2,para1:POINTER;Msg,Win:LONGWORD);ASM;
{This is the default window procedure for all objects called by PM.
 It is only called when the window is created and then redefined.
 As it has to be fast and low level programmed it is written in assembler...
 It will only call WinDefWnfProc and is redefined by WinSubClassWindow}
BEGIN
     ASM
        PUSH EBP
        MOV EBP,ESP
        PUSHL $para2
        PUSHL $para1
        PUSHL $msg
        PUSHL $win
        MOV AL,4
        CALLDLL PMWin,911   ;WinDefWindowProc
        ADD ESP,16
        LEAVE
        RETN32
     END;
END;

PROCEDURE InvalidateWindow(Win:HWND);
BEGIN
     WinInvalidateRect(1,NIL,Win);
END;


PROCEDURE DrawStringXY(_hps:HPS;VAR pt:POINTL;VAR s:string;start,Len:LONGWORD;
                       Color,BackColor:LONGWORD);
BEGIN
     GpiSetColor(Color,_hps);
     GpiSetBackColor(BackColor,_hps);
     GpiCharStringAt(s[Start],Len,pt,_hps);
END;


PROCEDURE MaximizeWindow(Win:HWND);
BEGIN
     WinSetWindowPos(SWP_MAXIMIZE OR SWP_ACTIVATE OR SWP_SHOW,0,0,0,0,
                     HWND_TOP,Win);
END;

PROCEDURE MinimizeWindow(Win:HWND);
BEGIN
     WinSetWindowPos(SWP_MINIMIZE OR SWP_ACTIVATE OR SWP_SHOW,0,0,0,0,
                     HWND_TOP,Win);
END;


PROCEDURE GetWindowPos(Win:HWND;VAR x,y,cx,cy:LONGINT);
VAR _swp:SWP;
BEGIN
     WinQueryWindowPos(_swp,Win);
     x:=_swp.x;
     y:=_swp.y;
     cx:=_swp.cx;
     cy:=_swp.cy;
END;

PROCEDURE SetWindowPos(Win:HWND;x,y,cx,cy:LONGINT);
BEGIN
     WinSetWindowPos(SWP_SPEED,cy,cx,y,x,HWND_TOP,Win);
END;

FUNCTION IsWindowMaximized(Win:HWND):BOOLEAN;
VAR r:LONGWORD;
BEGIN
     IF Win=0 THEN
     BEGIN
          IsWindowMaximized:=FALSE;
          exit;
     END;
     IF WinQueryWindowUShort(QWS_ID,Win)=FID_CLIENT THEN
      Win:=WinQueryWindow(QW_PARENT,Win);
     r:=WinQueryWindowULong(QWL_STYLE,Win) and WS_MAXIMIZED;
     IF r<>0 THEN IsWindowMaximized:=TRUE
     ELSE IsWindowMaximized:=FALSE;
END;

FUNCTION IsWindowMinimized(Win:HWND):BOOLEAN;
VAR r:LONGWORD;
BEGIN
     IF Win=0 THEN
     BEGIN
          IsWindowMinimized:=FALSE;
          exit;
     END;
     IF WinQueryWindowUShort(QWS_ID,Win)=FID_CLIENT THEN
      Win:=WinQueryWindow(QW_PARENT,Win);
     r:=WinQueryWindowULong(QWL_STYLE,Win) and WS_MINIMIZED;
     IF r<>0 THEN IsWindowMinimized:=TRUE
     ELSE IsWindowMinimized:=FALSE;
END;

PROCEDURE HideWindow(Win:HWND);
BEGIN
     WinSetWindowPos(SWP_HIDE,0,0,0,0,0,Win);
END;

PROCEDURE ShowWindow(Win:HWND);
BEGIN
     WinSetWindowPos(SWP_SHOW,0,0,0,0,0,Win);
END;

PROCEDURE DisableWindow(Win:HWND);
BEGIN
     WinEnableWindow(0,Win);
END;


PROCEDURE WindowToTop(FrameWin:HWND);
BEGIN
     WinSetWindowPos(SWP_ZORDER,0,0,0,0,HWND_TOP,FrameWin);
END;


PROCEDURE EnableWindow(Win:HWND);
BEGIN
     WinEnableWindow(1,Win);
END;

PROCEDURE RestoreWindow(Win:HWND);
BEGIN
     WinSetWindowPos(SWP_RESTORE,0,0,0,0,0,Win);
END;

FUNCTION ConfirmBox(Options:LONGWORD;msg:String):BOOLEAN;
VAR s:PString;
    result:LONGWORD;
BEGIN
     s:='Confirm action';
     result:=WinMessageBox(MB_YESNO or MB_MOVEABLE or MB_Query
                           or Options,0,s,msg,
                           HWND_DESKTOP{Frame},HWND_DESKTOP);
     ConfirmBox:=result=MBID_YES;
END;


PROCEDURE MessageBox(msg:String);
VAR s:PString;
BEGIN
     s:='Message';
     WinMessageBox(MB_OK or MB_MOVEABLE or MB_Query,0,s,msg,
                   HWND_DESKTOP{AppWinFrameHandle},HWND_Desktop);
END;

PROCEDURE ErrorBox(Options:LONGWORD;err:String);
VAR s:PString;
BEGIN
     s:='Error';
     WinMessageBox(MB_OK or MB_MOVEABLE or options,0,s,err,
                   HWND_DESKTOP{AppWinFrameHandle},HWND_Desktop);
END;


FUNCTION PointerToWord(p:POINTER):WORD;ASM;
BEGIN
     ASM
        MOV EBX,ESP
        MOV EAX,[EBX+4]
        RETN32 4
     END;
END;


{*************************************************************************
*                                                                        *
*                       Methods for object TWindow                       *
*                                                                        *
**************************************************************************}

PROCEDURE MessageHandler(para2,para1:POINTER;Msg,Win:LONGWORD);ASM;
{This is the window procedure called by PM.
 As it has to be fast and low level programmed it is written in assembler...
 It will call HandleEvent as a virtual method in the VMT}
BEGIN
     ASM
        PUSH EBP
        MOV EBP,ESP
        SUB ESP,2
        ;Save parameters as it is SYSTEM Calling Convention
        PUSH EDI
        PUSH ESI
        PUSH EBX

        MOVW [EBP-2],0   ;Not Handled

        PUSHL $Win
        PUSHL $Msg
        PUSHL $para1
        PUSHL $para2
        LEA EAX,[EBP-2]
        PUSH EAX

        PUSHL 0             ;Get VMT pointer
        PUSHL $Win
        MOV AL,2
        CALLDLL PMWIN,843   ;QueryWindowUlong
        ADD ESP,8
        MOV EDI,EAX
        PUSH EDI         ;VMT Pointer
        MOV EDI,[EDI+0]  ;get VMT pointer for HandleEvent
        db ffh,17h       ;CALL NEAR32 [EDI+0] --> in Methode springen
        MOV BL,[EBP-2]
        CMP BL,0
        JNE !hh
        ;not handled
        ;Default Window handler
        PUSHL $para2
        PUSHL $para1
        PUSHL $msg
        PUSHL $win
        MOV AL,4
        CALLDLL PMWin,911   ;WinDefWindowProc
        ADD ESP,16
!hh:
        ;Get registers as it is SYSTEM calling convention
        POP EBX
        POP ESI
        POP EDI
        LEAVE
        RETN32
     END;
END;


CONSTRUCTOR TWindow.Init;
{Global initialization of Object TWindow}
BEGIN
     Title:='';            {Window title}
     FontName:='Helv';     {Default font name}
     FontWidth:=8;         {Default font width}
     FontHeight:=8;        {Default font height}
     ForeColor:=CLR_BLACK; {Default output color}
     BackColor:=CLR_WHITE; {Default window background color}
END;

PROCEDURE TWindow.CreateWindow(Parent:HWND;Style,CreateFlags:LONGWORD;
                               Class,Title:String;StyleClient:LONGWORD;
                               Res,id:LONGWORD);
{Creates the window with the given parameters and subclasses
 Window procedure}
BEGIN
     FrameHandle:=WinCreateStdWindow(Parent,Style,CreateFLags,Class,Title,
                                     StyleClient,Res,id,ClientHandle);
     WinSetWindowULong(LONGWORD(SELF),0,ClientHandle); {VMT pointer}
     WinSubClassWindow(@MessageHandler,ClientHandle);
     DesktopClientHandle:=ClientHandle;
     DesktopFrameHandle:=FrameHandle;
END;

PROCEDURE TWindow.PrintString(ps:HPS;s:STRING;x,y:LONGINT);
VAR pt:POINTL;
BEGIN
     CreateLogFont(ps,FontName,FontWidth,FontHeight,0);
     GpiSetBackMix(2,ps);  {BM_OverPaint}
     pt.x:=x;
     pt.y:=y;
     DrawStringXY(ps,pt,s,1,Length(s),ForeColor,BackColor);
END;

PROCEDURE TWindow.GetMaxDesktopWindow(VAR _swp:SWP);
VAR rec:RECTL;
BEGIN
     WinQueryWindowRect(rec,DesktopClientHandle);
     _swp.cx:=rec.XRight-rec.XLeft;
     _swp.cy:=rec.yTop-rec.yBottom;
     _swp.x:=rec.xRight-_swp.cx;
     _swp.y:=rec.yTop-_swp.cy;
END;

PROCEDURE TWindow.SetColors(Col,BackCol:LONGINT);
{Set default colors}
BEGIN
     ForeColor:=Col;
     BackColor:=BackCol;
     InvalidateAppWindow;  {Forces a redraw}
END;

PROCEDURE TWindow.InvalidateAppWindow;
{Forces a redraw of the whole window client area}
BEGIN
     WinInvalidateRect(1,NIL,ClientHandle);
END;


PROCEDURE TWindow.DeleteData;
{Destroys all user defined data. This is a dummy}
BEGIN
END;

DESTRUCTOR TWindow.Done;
BEGIN
     DeleteData;
END;

PROCEDURE TWindow.Redraw(rc:RECTL;_hps:HPS;Win:HWND);
{Redraws the client area}
BEGIN
END;

PROCEDURE TWindow.WMEraseBackGround(Win:HWND;rc:RECTL;_hps:HPS);
{Fill the background with the default background color}
BEGIN
     WinFillRect(BackColor,rc,_hps);
END;

PROCEDURE TWindow.WMClose(VAR Msg:TMessage);
BEGIN
     WinDestroyWindow(WinQueryWindow(QW_PARENT,Msg.Win));
END;

PROCEDURE TWindow.WMCreate(VAR Msg:TMessage);
{Is called when the window is created}
BEGIN
END;

PROCEDURE TWindow.WMDestroy(VAR Msg:TMessage);
{Is called when the window is destroyed}
BEGIN
END;

PROCEDURE TWindow.WMActivate(VAR Msg:TMessage);
{Is called when the window is activated by the user}
BEGIN
END;

FUNCTION TWindow.MDIHandleEvent(Win:HWND;Msg:LONGWORD;
                                para1,para2:POINTER;
                                VAR Handled:BOOLEAN;Data:POINTER):LONGWORD;
{Window procedure for MDI child windows. This is a dummy}
BEGIN
     Handled:=FALSE;
     MDIHandleEvent:=0;
END;

PROCEDURE TWindow.WMButton1Down(Win:HWND;x,y:INTEGER);
{Is clicked when the left mouse button is pressed in the desktop area}
BEGIN
END;

PROCEDURE TWindow.WMButton1Up(Win:HWND;x,y:INTEGER);
{Is called when the left mouse button is released in the desktop area}
BEGIN
END;

PROCEDURE TWindow.WMButton1Click(Win:HWND;x,y:INTEGER);
{Is called when the left mouse button is clicked in the desktop area}
BEGIN
END;

PROCEDURE TWindow.WMButton1DoubleClick(Win:HWND;x,y:INTEGER);
{Is called when the left mouse button is clicked in the desktop area}
BEGIN
END;

PROCEDURE TWindow.WMButton2Down(Win:HWND;x,y:INTEGER);
{Is clicked when the right mouse button is pressed in the desktop area}
BEGIN
END;

PROCEDURE TWindow.WMButton2Up(Win:HWND;x,y:INTEGER);
{Is called when the right mouse button is released in the desktop area}
BEGIN
END;

PROCEDURE TWindow.WMButton2Click(Win:HWND;x,y:INTEGER);
{Is called when the right mouse button is clicked in the desktop area}
BEGIN
END;

PROCEDURE TWindow.WMMouseMove(Win:HWND;x,y:INTEGER);
{Is called when the mouse is moved in the desktop area}
BEGIN
END;

PROCEDURE TWindow.WMSize(VAR Msg:TMessage);
{Called when the window is sized. This is a dummy}
BEGIN
     Msg.Handled:=FALSE;
END;

PROCEDURE TWindow.SetWindowTitle(s:STRING);
BEGIN
     Title:=s;
     WinSetWindowText(s,DesktopFrameHandle);
END;

FUNCTION TWindow.DesktopHandleEvent(Win:HWND;Msg:LONGWORD;
                                    para1,para2:POINTER;
                                    VAR Handled:BOOLEAN):LONGWORD;
{Message handler for the desktop of the window}
VAR H:BOOLEAN;
    r:LONGWORD;
    po:POINTS;
BEGIN
     CASE Msg OF
        WM_BUTTON1DOWN,WM_BUTTON1CLICK,
        WM_BUTTON1DBLCLK,WM_BUTTON1UP,
        WM_BUTTON2DOWN,WM_BUTTON2CLICK,
        WM_BUTTON2UP,WM_MOUSEMOVE:WinSendMsg(para2,para1,Msg,AppWinHandle);
     END;
     Handled:=FALSE;
     DesktopHandleEvent:=0;
END;

PROCEDURE TWindow.HandleScanEvent(Win:HWND;scan:WORD);
{Handles scan events from the keyboard}
BEGIN
END;

PROCEDURE TWindow.HandleCharEvent(Win:HWND;Ch:CHAR);
{Handles char events from the keyboard}
BEGIN
END;

PROCEDURE TWindow.HandleCommand(Win:HWND;Command:WORD);
{Handles WM_COMMAND messages}
BEGIN
END;

PROCEDURE TWindow.GetPS(VAR ps:HPS);
BEGIN
     ps:=WinGetPS(DesktopClientHandle);
END;

PROCEDURE TWindow.ReleasePS(ps:HPS);
BEGIN
     WinReleasePS(ps);
END;

FUNCTION TWindow.HandleEvent(Win:HWND;Msg:LONGWORD;
                             para1,para2:POINTER;
                             VAR Handled:BOOLEAN):LONGWORD;
{Handles messages for the main window}
VAR
    H:Boolean;
    _hps:HPS;
    r:LONGWORD;
    w,w1:WORD;
    b:WORD;
    ch:CHAR;
    rc,rc1:RECTL;
    command:WORD;
    po:POINTS;
    _swp:SWP;
    _Msg:TMessage;
    DMTFound:BOOLEAN;
label l,l1,l3;
BEGIN
      _Msg.Win:=Win;
      _Msg.Para1:=LONGWORD(Para1);
      _Msg.Para2:=LONGWORD(Para2);
      _Msg.Message:=Msg;
      _Msg.Handled:=TRUE;
      _msg.Result:=0;
      DMTFound:=FALSE;
      {Check for dynamic methods}
      ASM
         MOV EDI,$!SELF
         MOV EDI,[EDI+4]   ;DMT table address
         MOV ECX,[EDI+0]   ;DMT table size
         SHR ECX,3         ;Divide by 8
         CMP ECX,0
         JE !NoDMT         ;no dynamic methods
         ADD EDI,4         ;onto first DMT entry
         MOV EAX,$Msg
!DMTLoop:
         CMP EAX,[EDI+0]
         JE !DMTHere       ;Message found
         ADD EDI,8         ;next DMT entry
         LOOP !DMTLoop
         JMP !NoDMT
!DMTHere:
         MOVB $DMTFound,1
         LEA EAX,$_Msg
         PUSH EAX          ;Parameter for dynamic method call
         MOV EAX,[EDI+4]   ;Method index in VMT
         DEC EAX
         SHL EAX,2         ;multiply with 4
         MOV EDI,$!SELF
         PUSH EDI          ;VMT for dynamic method
         MOV EDI,[EDI+0]   ;Get VMT address
         ADD EDI,EAX       ;Calculate method
         db ffh,17h       ;CALL NEAR32 [EDI+0] --> in Methode springen
!NoDMT:
      END;
      IF DMTFound THEN
      BEGIN
           H:=_Msg.Handled;
           r:=_Msg.Result;
           goto l1;
      END;
      r:=0;
      H:=TRUE;
      CASE Msg OF
          WM_ERASEBACKGROUND:
          BEGIN
               _hps:=WinBeginPaint(rc,0,Win);
               GetMaxDesktopWindow(_swp);
               rc1.yBottom:=_swp.y;
               rc1.xLeft:=_swp.x;
               rc1.yTop:=_swp.y+_swp.cy;
               rc1.xRight:=_swp.x+_swp.cx;
               WMEraseBackGround(Win,rc1,_hps);
               Redraw(rc,_hps,Win);
               WinEndPaint(_hps);
               H:=FALSE;
          END;
          WM_PAINT:
          BEGIN
               _hps:=WinBeginPaint(rc,0,Win);
               Redraw(rc,_hps,Win);
               WinEndPaint(_hps);
          END;
          WM_COMMAND:
          BEGIN
               command:=PointerToWord(para1);
               HandleCommand(Win,command);
          END;
          WM_CHAR:
          BEGIN
               H:=FALSE; {Not handled}
               r:=LONGINT(para1);
               w:=lo(r);
               IF w AND $41=1 THEN {KC_CHAR valid and KC_KEYUP}
               BEGIN
                    r:=LONGINT(para2);
                    w1:=lo(r);
                    b:=lo(w1);
                    if b<32 THEN goto l;
                    IF w and $10=$10 THEN goto l; {KC_CTRL valid}
                    IF w and $20=$20 THEN goto l; {KC_ALT valid}
                    ch:=chr(b);
                    InCtrlK:=FALSE;
                    HandleCharEvent(Win,ch);
                    H:=FALSE; {not handled}
                    r:=0;
                    goto l1;
               END
               ELSE
               BEGIN
                    IF w AND $44=4 THEN {KC_CHAR valid and KC_KEYUP}
                    BEGIN
                         w1:=hi(r);
                         b:=hi(w1);
l:
                         IF w and $10=$10 THEN {Ctrl-Taste}
                         BEGIN
                              inc(b,256); {KC_CTRL valid}
                              CASE b OF
                                 kbCtrlK:
                                 BEGIN
                                     IF InCtrlK THEN goto l3;
                                     InCtrlK:=TRUE;
                                 END
                                 ELSE
                                 BEGIN
                                     IF InCtrlK THEN
                                     BEGIN
l3:
                                          inc(b,1000);
                                     END;
                                     InCtrlK:=FALSE;
                                 END;
                              END; {Case}
                         END
                         ELSE
                         BEGIN
                              InCtrlK:=FALSE;
                              IF w AND 8=8 THEN inc(b,512) {KC_SHIFT valid}
                              ELSE IF w AND $20=$20 THEN inc(b,768); {KC_ALT valid}
                         END;
                         HandleScanEvent(Win,b);
                         H:=FALSE; {not handled}
                         r:=0;
                         goto l1;
                    END;
               END;
          END;
          WM_BUTTON1DOWN:
          BEGIN
               Drag_Mode:=FALSE;
               MouseButton1Down:=TRUE;
               po:=POINTS(para1);
               WMButton1Down(Win,po.x,po.y);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON1CLICK:
          BEGIN
               MouseButton1Down:=FALSE;
               Drag_Mode:=FALSE;
               po:=POINTS(para1);
               WMButton1Click(Win,po.x,po.y);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON1DBLCLK:
          BEGIN
               MouseButton1Down:=FALSE;
               Drag_Mode:=FALSE;
               po:=POINTS(para1);
               WMButton1DoubleClick(Win,po.x,po.y);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON1UP:
          BEGIN
               MouseButton1Down:=FALSE;
               Drag_Mode:=FALSE;
               po:=POINTS(para1);
               WMButton1Up(Win,po.x,po.y);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON2DOWN:
          BEGIN
               po:=POINTS(para1);
               WMButton2Down(Win,po.x,po.y);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON2CLICK:
          BEGIN
               po:=POINTS(para1);
               WMButton2Click(Win,po.x,po.y);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON2UP:
          BEGIN
               po:=POINTS(para1);
               WMButton2Up(Win,po.x,po.y);
               IF not Handled THEN H:=FALSE;
          END;
          WM_MOUSEMOVE:
          BEGIN
               IF MouseButton1Down THEN WinSendMsg(NIL,para1,WM_MOUSEDRAG1,Win);
               po:=POINTS(Para1);
               WMMouseMove(Win,po.x,po.y);
               IF not Handled THEN H:=FALSE;
          END;
          ELSE H:=FALSE;
      END;
l1:
      Handled:=H;
      HandleEvent:=r;
END;








{*************************************************************************
*                                                                        *
*                       Methods for object TApplication                  *
*                                                                        *
**************************************************************************}


PROCEDURE TApplication.GetMaxAppWindow(VAR _swp:SWP);
VAR rec:RECTL;
    XDiv,YDiv,UWin:LONGWORD;
BEGIN
     XDiv:=WinQuerySysValue(SV_CXSIZEBORDER,HWND_DESKTOP);
     XDiv:=XDiv+WinQuerySysValue(SV_CXMINMAXBUTTON,HWND_DESKTOP) DIV 2;

     YDiv:=WinQuerySysValue(SV_CYSIZEBORDER,HWND_DESKTOP);
     YDiv:=YDiv+WinQuerySysValue(SV_CYMINMAXBUTTON,HWND_DESKTOP);
     WinQueryWindowRect(rec,ClientHandle);
     _swp.cx:=rec.XRight-rec.XLeft;
     _swp.cy:=rec.yTop-rec.yBottom;
     _swp.x:=rec.xRight-_swp.cx;
     _swp.y:=rec.yTop-_swp.cy;

     dec(_swp.cy,ToolBarSize);
     dec(_swp.cy,StatusBarSize);

     dec(_swp.cx,RightToolBarSize);
     dec(_swp.cx,LeftToolBarSize);

     inc(_swp.x,LeftToolBarSize);
     inc(_swp.y,StatusBarSize);
END;

PROCEDURE TApplication.PopupMenu(VAR Menu:HWND;id:LONGWORD;
                                       x,y:LONGWORD;Parent:HWND);
BEGIN
     IF Menu=0 THEN Menu:=WinLoadMenu(id,0,HWND_OBJECT);
     WinPopupMenu(PU_HCONSTRAIN OR PU_VCONSTRAIN OR PU_KEYBOARD OR
                  PU_MOUSEBUTTON2 OR PU_MOUSEBUTTON1,0,y,x,Menu,Parent,
                  Parent);
END;

PROCEDURE TApplication.DisplayHelp(PanelID:WORD);
VAR
   p2:LONGWORD;
BEGIN
     IF HelpWindow=0 THEN exit;
     p2:=0;  {HM_RESOURCEID}
     WinSendMsg(POINTER(p2),POINTER(PanelID),HM_DISPLAY_HELP,HelpWindow);
END;

PROCEDURE TApplication.WMMenuSelect(Win:HWND;para1:POINTER);
BEGIN
END;

FUNCTION TApplication.HandleEvent(Win:HWND;Msg:LONGWORD;
                              para1,para2:POINTER;
                              VAR Handled:BOOLEAN):LONGWORD;
VAR
    H:Boolean;
    _hps:HPS;
    r:LONGWORD;
    command:WORD;
    rc:RECTL;
    w,w1:Word;
    b:WORD;
    ch:char;
    _swp:swp;
    xdiv,ydiv,err:LONGWORD;
    dummy:PMenuHelpItems;
    status:PStatusBarInterior;
label l,l1,l2;
BEGIN
     r:=Inherited.HandleEvent(Win,Msg,para1,para2,handled);
     r:=0;
     H:=TRUE;
     CASE Msg OF
          HM_QUERY_KEYS_HELP:r:=CM_KEYSHELP;
          HM_ERROR:
          BEGIN
               err:=LONGWORD(Para1);
               ErrorBox(MB_ICONHAND,'Help manager error '+tostr(err));
          END;
          HM_HELPSUBITEM_NOT_FOUND:ErrorBox(MB_ICONHAND,'Helpsubitem not found!');
          HM_EXT_HELP_UNDEFINED:ErrorBox(MB_ICONHAND,'Extended help undefined!');
          HM_GENERAL_HELP_UNDEFINED:ErrorBox(MB_ICONHAND,'General help undefined!');
          WM_MENUSELECT:
          BEGIN
               WMMenuSelect(Win,para1);
               IF StatusBarSize=0 THEN goto l2;
               w:=WORD(para1);
               w1:=0;
               dummy:=MenuHelpItems;
               WHILE dummy<>NIL DO
               BEGIN
                    IF dummy^.MenuID=65535 THEN w1:=dummy^.StatusID;
                    IF dummy^.MenuID=w THEN
                    BEGIN
                         w1:=dummy^.StatusID;
                         Status:=StatusBarInterior;
                         WHILE Status<>NIL DO
                         BEGIN
                              IF Status^.ID=w1 THEN
                              BEGIN
                                   StatusBarSetText(w1,dummy^.HelpText,
                                                    dummy^.Col);
                                   goto l2;
                              END;
                              Status:=Status^.Next;
                         END;
                         goto l2;
                    END;
                    dummy:=dummy^.Next;
               END;
               IF w1<>0 THEN StatusBarSetText(w1,'',-1);
l2:
               IF not Handled THEN H:=FALSE;
          END;
          WM_MENUEND:
          BEGIN
               dummy:=MenuHelpItems;
               WHILE dummy<>NIL DO
               BEGIN
                    IF dummy^.MenuID=65535 THEN
                    BEGIN
                         StatusBarSetText(dummy^.StatusID,dummy^.HelpText,
                                          dummy^.Col);
                         goto l2;
                    END;
               END;
               IF not Handled THEN H:=FALSE;
          END;
          ELSE IF not Handled THEN H:=FALSE;
     END;
l1:
     Handled:=H;
     HandleEvent:=r;
END;

PROCEDURE TApplication.WMSize(VAR Msg:TMessage);
VAR _swp:SWP;
BEGIN
     Inherited.WMSize(Msg);
     GetMaxAppWindow(_swp);
     WinSetWindowPos(SWP_SPEED,_swp.cy,_swp.cx,_swp.y,_swp.x,
                     HWND_TOP,DesktopFrameHandle);
END;

PROCEDURE TApplication.WMClose(VAR Msg:TMessage);
BEGIN
     WinPostMsg(NIL,NIL,WM_QUIT,Msg.Win);
END;


CONSTRUCTOR TApplication.Init;
BEGIN
     Inherited.Init;
     AlternateExit:=TRUE; {Set alternate WM_QUIT Handler}
     ToolBarSize:=0;
     LeftToolBarSize:=0;
     RightToolBarSize:=0;
     StatusBarSize:=0;
     ToolBarInterior:=NIL;
     StatusBarInterior:=NIL;
     MenuHelpItems:=NIL;
     WindowID:=0;
     HasMenu:=FALSE;  {TRUE for Menu resource}
     HasIcon:=FALSE;  {TRUE for Icon resource}
     HasAccel:=FALSE; {TRUE for Accel resource}
     HasHelp:=FALSE;  {TRUE for online help}
     Wincx:=450;
     Wincy:=350;
     Winx:=50;
     Winy:=100;
END;

DESTRUCTOR TApplication.Done;
BEGIN
     Inherited.Done;
END;

PROCEDURE MainMessageLoop;
VAR _qmsg:QMSG;
BEGIN
     ASM
!ndis:
        PUSHL 0    ;PM_NOREMOVE
        PUSHL 0
        PUSHL 0
        PUSHL 0
        LEA EAX,$_qmsg
        PUSH EAX
        PUSHL _AppHandle
        MOV AL,6
        CALLDLL PMWIN,918  ;WinPeekMsg
        ADD ESP,24
        CMP EAX,0         ;Message in the queue ??
        JNE !mes_here

        ;There was no message in the queue
        CMPB _Drag_Mode,0
        JE !mes_here       ;Wait for next message

        ;Create a WM_MouseDRAG Message at last Message Position
        PUSHL 0
        PUSHL _LastDragPos
        PUSHL 1000h   ;WM_MOUSEDRAG1
        PUSHL _DragWindow
        MOV AL,4
        CALLDLL PMWIN,920       ;WinSendMsg
        ADD ESP,16

        JMP !ndis
!mes_here:
        PUSHL 0
        PUSHL 0
        PUSHL 0
        LEA EAX,$_qmsg
        PUSH EAX
        PUSHL _AppHandle
        MOV AL,5
        CALLDLL PMWIN,915  ;WinGetMsg
        ADD ESP,20
        CMP EAX,0
        JE !exdis

        LEA ESI,$_qmsg
        MOV EAX,[ESI+4]     ;qmsg.msg
        CMP EAX,72h         ;WM_Button1Up
        JE !naus
        CMP EAX,0412h       ;WM_Button1MotionEnd
        JNE !naus_1
!naus:
        MOVB _MouseButton1Down,0
        MOVB _Drag_Mode,0
!naus_1:
        LEA EAX,$_qmsg
        PUSH EAX
        PUSHL _AppHandle
        MOV AL,2
        CALLDLL PMWIN,912  ;WinDispatchMsg
        ADD ESP,8
        JMP !ndis
!exdis:
     END;
END;

PROCEDURE TApplication.InsertResources(Menu,Accel,Icon:BOOLEAN);
BEGIN
     HasMenu:=Menu;
     HasAccel:=Accel;
     HasIcon:=Icon;
END;

PROCEDURE TApplication.StatusBarInsertItem(id:WORD;x,y,cx,cy:LONGWORD);
VAR
   dummy:PStatusBarInterior;
BEGIN
     IF StatusBarInterior=NIL THEN
     BEGIN
          New(StatusBarInterior);
          dummy:=StatusBarInterior;
     END
     ELSE
     BEGIN
          dummy:=StatusBarInterior;
          WHILE dummy^.Next<>NIL do dummy:=dummy^.next;
          new(dummy^.next);
          dummy:=dummy^.next;
     END;
     dummy^.id:=id;
     dummy^.x:=x;
     dummy^.y:=y;
     dummy^.cx:=cx;
     dummy^.cy:=cy;
     dummy^.item:='';
     dummy^.Next:=NIL;
     dummy^.Col:=-1;  {Black}
END;

PROCEDURE TApplication.SetMenuState(id:WORD;State:BOOLEAN);
VAR
   HwndMenu:HWND;
   w,w1:WORD;
   p,p1:POINTER;
BEGIN
     HwndMenu:=WinWindowFromID($8005{FID_MENU},FrameHandle);
     p:=MPFROM2SHORT(id,1);
     w:=$4000;  {Bitmaske MIA_Disabled}
     IF State=FALSE THEN w1:=$4000 {Disabled}
     ELSE w1:=0;  {Enabled}
     p1:=MPFROM2SHORT(w,w1);
     WinSendMsg(p1,p,$0192{MM_SETITEMATTR},HwndMenu);
END;

PROCEDURE TApplication.ToolBarInsertControl(id,x,y,cx,cy,flag,class:LONGWORD;
                                            title:STRING);
VAR
    Win:HWND;
    dummy:PToolBarInterior;
BEGIN
     Win:=WinCreateWindow(NIL,NIL,id,HWND_TOP,ClientHandle,cy,cx,y,x,Flag,
                     title,class,ClientHandle);
     IF ToolBarInterior=NIL THEN
     BEGIN
          New(ToolBarInterior);
          dummy:=ToolBarInterior;
     END
     ELSE
     BEGIN
          dummy:=ToolBarInterior;
          WHILE dummy^.Next<>NIL do dummy:=dummy^.next;
          new(dummy^.next);
          dummy:=dummy^.next;
     END;
     dummy^.Win:=Win;
     dummy^.id:=id;
     dummy^.x:=x;
     dummy^.y:=y;
     dummy^.cx:=cx;
     dummy^.cy:=cy;
     dummy^.Next:=NIL;
END;


PROCEDURE TApplication.ToolBarInsertButton(id,res,x,y,cx,cy:LONGWORD);
VAR title:string;
    fr,class:LONGWORD;
    flag:LONGWORD;
BEGIN
     IF res<>0 THEN title:='#'+tostr(res)
     ELSE title:='';
     fr:=0;
     Class:=$ffff0003;
     IF res=0 THEN Flag:=0  {No icon}
     ELSE Flag:=$0840;
     ToolBarInsertControl(id,x,y,cx,cy,Flag,Class,title);
END;

PROCEDURE TApplication.CreateToolBar(Size:WORD);
BEGIN
     ToolBarSize:=Size;
END;

PROCEDURE TApplication.CreateLeftToolBar(Size:WORD);
BEGIN
     LeftToolBarSize:=Size;
END;

PROCEDURE TApplication.CreateRightToolBar(Size:WORD);
BEGIN
     RightToolBarSize:=Size;
END;

PROCEDURE TApplication.InsertMenuHelp(StatusID,MenuID:WORD;
                                    HelpText:String;Col:LONGWORD);
VAR
   dummy:PMenuHelpItems;
BEGIN
     IF MenuHelpItems=NIL THEN
     BEGIN
          New(MenuHelpItems);
          dummy:=MenuHelpItems;
     END
     ELSE
     BEGIN
          dummy:=MenuHelpItems;
          WHILE dummy^.Next<>NIL DO dummy:=dummy^.next;
          New(dummy^.Next);
          dummy:=dummy^.Next;
     END;
     dummy^.StatusID:=StatusID;
     dummy^.MenuID:=MenuID;
     dummy^.Col:=Col;
     dummy^.HelpText:=Helptext;
     dummy^.Next:=NIL;
END;

PROCEDURE TApplication.CreateStatusBar(Size:WORD);
VAR Title:STRING;
    fr:LONGWORD;
    _swp:SWP;
BEGIN
     StatusBarSize:=Size;
END;

PROCEDURE TApplication.AppCreateNotify(AppFrWin,AppWin:HWND);
BEGIN
     WinSetWindowPos(SWP_SPEED,WinCY,WinCX,WinY,WinX,HWND_TOP,AppFrWin);
END;

PROCEDURE TApplication.AppRunNotify(AppFrWin:HWND);
BEGIN
END;

PROCEDURE TApplication.HandleCommand(Win:HWND;command:WORD);
VAR Msg:TMessage;
BEGIN
     Inherited.HandleCommand(Win,command);
     CASE command OF
         CM_HELPONHELP:IF HelpWindow<>0 THEN
                WinSendMsg(NIL,NIL,HM_DISPLAY_HELP,HelpWindow);
         CM_EXTENDEDHELP:IF HelpWindow<>0 THEN
                WinSendMsg(NIL,NIL,HM_EXT_HELP,HelpWindow);
         CM_KEYSHELP:IF HelpWindow<>0 THEN
                WinSendMsg(NIL,NIL,HM_KEYS_HELP,HelpWindow);
         CM_HELPINDEX:IF HelpWindow<>0 THEN
                WinSendMsg(NIL,NIL,HM_HELP_INDEX,HelpWindow);
         CM_HELPCONTENTS:IF HelpWindow<>0 THEN
                WinSendMsg(NIL,NIL,HM_HELP_CONTENTS,HelpWindow);
         CM_QUIT:
         BEGIN
              Msg.Win:=Win;
              Msg.Message:=WM_CLOSE;
              WMClose(Msg);
         END;
     END; {case}
END;

PROCEDURE DesktopHandler(para2,para1:POINTER;Msg,Win:LONGWORD);ASM;
BEGIN
     ASM
        PUSH EBP
        MOV EBP,ESP
        SUB ESP,2
        ;Save parameters as it is SYSTEM Calling Convention
        PUSH EDI
        PUSH ESI
        PUSH EBX

        MOVW [EBP-2],0   ;Not Handled
        PUSHL $Win
        PUSHL $Msg
        PUSHL $para1
        PUSHL $para2
        LEA EAX,[EBP-2]
        PUSH EAX

        PUSHL 0             ;Get VMT pointer
        PUSHL $Win
        MOV AL,2
        CALLDLL PMWIN,843   ;QueryWindowUlong
        ADD ESP,8
        MOV EDI,EAX
        PUSH EDI         ;VMT Pointer
        MOV EDI,[EDI+0]  ;get VMT pointer for DesktopHandleEvent
        ADD EDI,8
        db ffh,17h       ;CALL NEAR32 [EDI+0] --> in Methode springen
        MOV BL,[EBP-2]
        CMP BL,0
        JNE !hh1
        ;not handled
        ;Default Window handler
        PUSHL $para2
        PUSHL $para1
        PUSHL $msg
        PUSHL $win
        MOV AL,4
        CALLDLL PMWin,911   ;WinDefWindowProc
        ADD ESP,16
!hh1:
        ;Get registers as it is SYSTEM calling convention
        POP EBX
        POP ESI
        POP EDI
        LEAVE
        RETN32
     END;
END;


PROCEDURE TApplication.SetupMenu(Frame,Client:HWND);
BEGIN
END;


PROCEDURE TApplication.Run(id:LONGWORD;Title:String;Col,BCol:LONGINT);
VAR fr:LONGWORD;
    ti:string;
    p:POINTER;
    HelpInit:THelpInit;
    _swp:SWP;
    _hps:HPS;
    rc:RECTL;
BEGIN
     WindowID:=Id;
     ChildIconRes:=Id;
     fr:=FCF_SIMPLE;
     IF HasMenu THEN fr:=fr OR FCF_MENU;
     IF HasIcon THEN fr:=fr OR FCF_ICON;
     IF HasAccel THEN fr:=fr OR FCF_ACCELTABLE;
     CreateWindow(HWND_DESKTOP,0,fr,TWindowClass,Title,0,0,WindowID);
     ForeColor:=Col;
     BackColor:=BCol;
     AppWinHandle:=ClientHandle;
     AppWinFrameHandle:=FrameHandle;

     fr:=0;
     DesktopFrameHandle:=WinCreateStdWindow(ClientHandle,0,fr,
                                            TDesktopWindowClass,Title,
                                            0,0,0,DesktopClientHandle);
     WinSetWindowULong(LONGWORD(SELF),0,DesktopClientHandle); {VMT pointer}
     WinSubClassWindow(@DesktopHandler,DesktopClientHandle);
     HelpWindow:=0;
     IF HasHelp THEN
     BEGIN
          p:=@helptitle;
          inc(p);
          HelpInit.pszHelpWindowTitle:=p;
          p:=@HelpFileName;
          inc(p);
          HelpInit.pszHelpLibraryName:=p;
          HelpInit.cb:=sizeof(THelpInit);
          HelpInit.ulReturnCode:=0;
          HelpInit.pszTutorialname:=NIL;
          HelpInit.phtHelptable:=$FFFF0000 OR WindowID;
          HelpInit.hmodHelptableModule:=0;
          HelpInit.hmodAccelActionBarModule:=0;
          HelpInit.idAcceltable:=0;
          HelpInit.idActionBar:=0;
          HelpInit.fShowPanelID:=1;
          HelpWindow:=WinCreateHelpInstance(HelpInit,Apphandle);

          IF HelpWindow<>0 THEN
          BEGIN
               WinAssociateHelpInstance(FrameHandle,HelpWindow);
          END
          ELSE ErrorBox(MB_ICONHAND,'Application failed to initialize help');
     END;

     AppCreateNotify(FrameHandle,ClientHandle);
     SetupMenu(FrameHandle,ClientHandle);
     WindowToTop(FrameHandle);
     GetMaxAppWindow(_swp);
     WinSetWindowPos(SWP_SPEED,_swp.cy,_swp.cx,_swp.y,_swp.x,HWND_TOP,
                     DesktopFrameHandle);
     _hps:=WinGetPS(ClientHandle);
     WinQueryWindowRect(rc,ClientHandle);
     IF ToolBarSize>0 THEN RedrawToolBar(rc,_hps);
     IF StatusBarSize>0 THEN RedrawStatusBar(rc,_hps);
     IF LeftToolBarSize>0 THEN RedrawLeftToolBar(rc,_hps);
     IF RightToolBarSize>0 THEN RedrawRightToolBar(rc,_hps);
     WinReleasePS(_hps);
     AppRunNotify(ClientHandle);
     MainMessageLoop;
     WinDestroyWindow(FrameHandle);
END;

PROCEDURE TApplication.StatusBarSetText(id:WORD;item:STRING;
                                              Col:LONGINT);
VAR
   dummy:PStatusBarInterior;
   FaceName:String;
   _hps:HPS;
   rc:rectl;
   pt:POINTL;
BEGIN
     dummy:=StatusBarInterior;
     WHILE dummy<>NIL DO
     BEGIN
          IF dummy^.id=id THEN
          BEGIN
               dummy^.Col:=Col;
               IF dummy^.item=item THEN exit;
               dummy^.item:=item;
               _hps:=WinGetPS(ClientHandle);
               facename:='Helv';
               CreateLogFont(_hps,facename,13,5,0); {default font}
               GpiSetBackMix(2,_hps);  {BM_OverPaint}
               rc.xleft:=dummy^.x+2;
               rc.yBottom:=dummy^.y+2;
               rc.xright:=dummy^.x+dummy^.cx;
               dec(rc.xright,2);
               rc.yTop:=dummy^.y+dummy^.cy;
               dec(rc.ytop,2);
               WinFillRect(15,rc,_hps);
               pt.x:=dummy^.x+2;
               pt.y:=dummy^.y+4;
               IF dummy^.item<>'' THEN DrawStringXY(_hps,pt,dummy^.item,
                           1,length(dummy^.item),dummy^.Col,15);
               WinReleasePS(_hps);
               exit;
          END;
          dummy:=dummy^.next;
     END;
END;

PROCEDURE TApplication.DesktopRedraw(rc:RECTL;_hps:HPS;Win:HWND);
BEGIN
     WinFillRect(BackColor,rc,_hps);
END;

PROCEDURE TApplication.DesktopEraseBackGround(Win:HWND;rc:RECTL;_hps:HPS);
BEGIN
     WinFillRect(BackColor,rc,_hps);
END;

PROCEDURE TApplication.RedrawToolBar(rc:RECTL;_hps:HPS);
VAR
   _swp:swp;
   dummy:PToolBarInterior;
   ypos,xpos:LONGWORD;
BEGIN
     rc.yBottom:=rc.yTop-ToolBarSize;
     WinFillRect(15,rc,_hps);
     WinDrawBorder($800,-2,8,1,1,rc,_hps);

     GetMaxDesktopWindow(_swp);
     ypos:=_swp.y+_swp.cy+StatusBarSize;
     xpos:=_swp.x;
     dummy:=ToolBarInterior;
     WHILE dummy<>NIL DO
     BEGIN
         WinSetWindowPos(SWP_ACT,dummy^.CY,dummy^.CX,ypos+dummy^.Y,
                         xpos+dummy^.X,HWND_TOP,dummy^.Win);
         dummy:=dummy^.next;
     END;
END;

PROCEDURE TApplication.RedrawLeftToolBar(rc:RECTL;_hps:HPS);
VAR
   _swp:swp;
   dummy:PToolBarInterior;
   ypos,xpos:LONGWORD;
BEGIN
     dec(rc.yTop,ToolBarSize);
     inc(rc.yBottom,StatusBarSize);
     rc.xright:=rc.xleft+LeftToolBarSize;
     WinFillRect(15,rc,_hps);
     WinDrawBorder($800,-2,8,1,1,rc,_hps);

     {GetMaxDesktopWindow(_swp);
     ypos:=_swp.y+_swp.cy+StatusBarSize;
     xpos:=_swp.x;
     dummy:=ToolBarInterior;
     WHILE dummy<>NIL DO
     BEGIN
         WinSetWindowPos(SWP_ACT,dummy^.CY,dummy^.CX,ypos+dummy^.Y,
                         xpos+dummy^.X,HWND_TOP,dummy^.Win);
         dummy:=dummy^.next;
     END;}
END;

PROCEDURE TApplication.RedrawRightToolBar(rc:RECTL;_hps:HPS);
VAR
   _swp:swp;
   dummy:PToolBarInterior;
   ypos,xpos:LONGWORD;
BEGIN
     dec(rc.yTop,ToolBarSize);
     inc(rc.yBottom,StatusBarSize);
     rc.xleft:=rc.xright-RightToolBarSize;
     WinFillRect(15,rc,_hps);
     WinDrawBorder($800,-2,8,1,1,rc,_hps);

     {GetMaxDesktopWindow(_swp);
     ypos:=_swp.y+_swp.cy+StatusBarSize;
     xpos:=_swp.x;
     dummy:=ToolBarInterior;
     WHILE dummy<>NIL DO
     BEGIN
         WinSetWindowPos(SWP_ACT,dummy^.CY,dummy^.CX,ypos+dummy^.Y,
                         xpos+dummy^.X,HWND_TOP,dummy^.Win);
         dummy:=dummy^.next;
     END;}
END;

PROCEDURE TApplication.RedrawStatusBar(rc:RECTL;_hps:HPS);
VAR
   dummy:PStatusBarInterior;
   facename:STRING;
   pt:POINTL;
BEGIN
     rc.yTop:=rc.yBottom+StatusBarSize;
     WinFillRect(15,rc,_hps);
     WinDrawBorder($800,-2,8,1,1,rc,_hps);
     facename:='Helv';
     CreateLogFont(_hps,facename,13,5,0); {default font}
     GpiSetBackMix(2,_hps);  {BM_OverPaint}
     dummy:=StatusBarInterior;
     WHILE dummy<>NIL DO
     BEGIN
          rc.xleft:=dummy^.x;
          rc.yBottom:=dummy^.y;
          rc.xright:=dummy^.x+dummy^.cx;
          rc.yTop:=dummy^.y+dummy^.cy;
          WinDrawBorder($800,-2,8,1,1,rc,_hps);
          pt.x:=dummy^.x+2;
          pt.y:=dummy^.y+4;
          IF dummy^.item<>'' THEN DrawStringXY(_hps,pt,dummy^.item,
                             1,length(dummy^.item),dummy^.Col,15);
          dummy:=dummy^.next;
     END;
END;

PROCEDURE TApplication.Redraw(rc:RECTL;_hps:HPS;Win:HWND);
VAR
    maxy,miny:LONGINT;
    _swp:SWP;
BEGIN
     Inherited.Redraw(rc,_hps,Win);
     GetMaxAppWindow(_swp);
     rc.xLeft:=_swp.x;
     rc.xright:=_swp.x+_swp.cx+LeftToolBarSize;
     rc.yBottom:=_swp.y;
     rc.yTop:=_swp.y+_swp.cy;
     WinQueryWindowRect(rc,Win);
     WinFillRect(BackColor,rc,_hps);

     WinQueryWindowRect(rc,ClientHandle);
     IF ToolBarSize>0 THEN RedrawToolBar(rc,_hps);
     IF StatusBarSize>0 THEN RedrawStatusBar(rc,_hps);
     IF LeftToolBarSize>0 THEN RedrawLeftToolBar(rc,_hps);
     IF RightToolBarSize>0 THEN RedrawRightToolBar(rc,_hps);
END;

FUNCTION TApplication.DesktopHandleEvent(Win:HWND;Msg:LONGWORD;
                                     para1,para2:POINTER;
                                     VAR Handled:BOOLEAN):LONGWORD;
VAR
    H:Boolean;
    _hps:HPS;
    r:LONGWORD;
    command:WORD;
    rc:RECTL;
    w,w1:Word;
    b:WORD;
    ch:char;
label l,l1;
BEGIN
      r:=Inherited.DesktopHandleEvent(Win,Msg,para1,para2,handled);
      H:=TRUE;
      CASE Msg OF
          WM_ERASEBACKGROUND:
          BEGIN
               _hps:=WinBeginPaint(rc,0,Win);
               DesktopRedraw(rc,_hps,Win);
               WinEndPaint(_hps);
               H:=FALSE;
          END;
          WM_PAINT:
          BEGIN
               _hps:=WinBeginPaint(rc,0,Win);
               DesktopRedraw(rc,_hps,Win);
               WinEndPaint(_hps);
          END;
          ELSE IF not Handled THEN H:=FALSE;
      END;
l1:
      Handled:=H;
      DesktopHandleEvent:=r;
END;

PROCEDURE TApplication.InsertHelp(Filename,WindowTitle:String);
BEGIN
     HasHelp:=TRUE;
     HelpFileName:=FileName;
     HelpTitle:=Windowtitle;
END;







{*************************************************************************
*                                                                        *
*                      Methods for TMDIApplication                       *
*                                                                        *
**************************************************************************}

CONSTRUCTOR TMDIApplication.Init;
BEGIN
     Inherited.Init;
     ChildCount:=0;
     ActiveChild:=0;
     MinimizedCount:=0;
END;

DESTRUCTOR TMDIApplication.Done;
BEGIN
END;

PROCEDURE TMDIApplication.AppRunNotify(AppFrWin:HWND);
BEGIN
     Inherited.AppRunNotify(AppFrWin);
     SetMenuState(CM_TILE,FALSE);
     SetMenuState(CM_CASCADE,FALSE);
     SetMenuState(CM_CLOSE,FALSE);
     SetMenuState(CM_CLOSEALL,FALSE);
     SetMenuState(CM_NEXT,FALSE);
     SetMenuState(CM_LIST,FALSE);
END;


PROCEDURE TMDIApplication.TileWindows;
VAR
    Buf:PSWPBUF;
    Square,Rows,Columns,ExtraCols,Width,Height:LONGWORD;
    rec:RECTL;
    Child:HWND;
    _hEnum:LONGWORD;
    CurRow,CurCol:LONGWORD;
    ChildCnt:LONGWORD;
    t:LONGWORD;
    Win:HWND;
    TotalCount:BYTE;
LABEL l;
BEGIN
     TotalCount:=0;
     Win:=DesktopClientHandle;
     Square:=2;
     ChildCnt:=ChildCount-MinimizedCount;
     IF ChildCnt=0 THEN exit;
     WHILE Square*2<=ChildCnt DO inc(Square);
     IF ChildCnt=3 THEN Square:=3;

     Columns:=Square-1;
     Rows:=ChildCnt DIV Columns;
     ExtraCols:=ChildCnt MOD Columns;

     WinQueryWindowRect(rec,Win);
     IF rec.xRight>0 THEN IF rec.yBottom<rec.yTop THEN
     BEGIN
          _hEnum:=WinBeginEnumWindows(Win);
          Child:=WinGetNextWindow(_hEnum);
          IF Child<>0 THEN
          BEGIN
               GetMem(Buf,sizeof(TSWPBUF)*ChildCount);
               ChildCnt:=0;
               Height:=(rec.yTop-rec.yBottom) div Rows;

               FOR CurRow:=0 TO Rows-1 DO
               BEGIN
                    IF Rows-CurRow<=ExtraCols THEN inc(Columns);
                    FOR CurCol:=0 TO Columns-1 DO
                    BEGIN
                         Width:=rec.xRight div Columns;

                         {Skip minimized Windows}
l:
                         IF ((IsWindowMinimized(Child)))
                         {OR (WinQueryWindowUShort(QWS_ID,Child)=0))} THEN
                         BEGIN
                              Child:=WinGetNextWindow(_hEnum);
                              If Child<>0 THEN goto l;
                         END;

                         IF Child<>0 THEN
                         BEGIN
                              inc(TotalCount);
                              IF IsWindowMaximized(Child) THEN
                               Buf^[ChildCnt].fl:=SWP_SPEED OR SWP_RESTORE
                              ELSE Buf^[ChildCnt].fl:=SWP_SPEED;
                              buf^[ChildCnt].x:=Width*CurCol;
                              buf^[ChildCnt].y:=rec.yTop-(Height*(CurRow+1));
                              buf^[ChildCnt].cx:=Width;
                              buf^[ChildCnt].cy:=Height;
                              buf^[ChildCnt].ahwnd:=Child;
                              inc(ChildCnt);

                              Child:=WinGetNextWindow(_hEnum);
                         END;
                    END;
                    IF Rows-CurRow<=ExtraCols THEN
                    BEGIN
                         dec(Columns);
                         dec(ExtraCols);
                    END;
               END;

               WinEndEnumWindows(_HEnum);
               IF TotalCount>0 THEN WinSetMultWindowPos(TotalCount,
                                                        Buf^[0],AppHandle);
               FreeMem(Buf,sizeof(TSWPBUF)*ChildCount);
          END;

     END;
END;

PROCEDURE TMDIApplication.CascadeWindows;
VAR Next:HWND;
    Count:LONGWORD;
    Buf:PLONGBUF;
    t:LONGWORD;
    _swp:SWP;
    XDiv,YDiv:LONGWORD;
    Frame:HWND;
    Win:HWND;
BEGIN
     Win:=DesktopClientHandle;
     If ChildCount-MinimizedCount=0 THEN exit;
     XDiv:=WinQuerySysValue(SV_CXSIZEBORDER,HWND_DESKTOP);
     XDiv:=XDiv+WinQuerySysValue(SV_CXMINMAXBUTTON,HWND_DESKTOP) DIV 2;

     YDiv:=WinQuerySysValue(SV_CYSIZEBORDER,HWND_DESKTOP);
     YDiv:=YDiv+WinQuerySysValue(SV_CYMINMAXBUTTON,HWND_DESKTOP);
     Next:=WinQueryWindow(QW_TOP,Win);
     if Next=0 THEN exit;
     Count:=0;
     GetMem(Buf,4*ChildCount);
     WHILE ((Next<>0)AND(Count<ChildCount)) DO
     BEGIN
          IF ((not IsWindowMinimized(Next))){AND
             (WinQueryWindowUShort(QWS_ID,Next)<>0))}
          THEN
          BEGIN
               Buf^[Count]:=Next;
               Inc(Count);
          END;
          Next:=WinQueryWindow(QW_NEXT,Next);
     END;
     GetMaxDesktopWindow(_swp);
     FOR t:=0 TO Count-1 DO
     BEGIN
          WinSetWindowPos(SWP_SPEED,_swp.cy,_swp.cx,_swp.y,_swp.x,0,
                          Buf^[t]);
          inc(_swp.x,XDiv);
          dec(_swp.cx,XDiv);
          dec(_swp.cy,YDiv);
     END;
     FreeMem(Buf,4*ChildCount);
END;

PROCEDURE TMDIApplication.InvalidateMDIWindow(Win:HWND);
BEGIN
     WinInvalidateRect(1,NIL,Win);
END;

PROCEDURE TMDIApplication.NextWindow;
VAR Next:HWND;
    AcFrame:HWND;
    f:LONGWORD;
BEGIN
     Next:=WinQueryWindow(QW_PARENT,ActiveChild);
     AcFrame:=Next;
     Next:=WinQueryWindow(QW_NEXT,Next);
     WHILE ((Next<>0)AND(WinQueryWindowUShort(QWS_ID,Next)=0)) DO
       Next:=WinQueryWindow(QW_NEXT,Next);
     IF Next<>0 THEN
     BEGIN
           WinSetWindowPos(SWP_ZORDER or SWP_ACTIVATE,0,0,0,0,HWND_TOP,
                           Next);
           IF IsWindowMaximized(AcFrame) THEN f:=SWP_RESTORE OR SWP_ZORDER
           ELSE f:=SWP_ZORDER;
           WinSetWindowPos(f,0,0,0,0,HWND_BOTTOM,AcFrame);
     END;
END;

PROCEDURE TMDIApplication.CloseAllWindows;
VAR Child:HWND;
    _hEnum:LONGWORD;
    Win:HWND;
BEGIN
     Win:=DesktopClientHandle;
     _hEnum:=WinBeginEnumWindows(Win);
     Child:=WinGetNextWindow(_HEnum);
     WHILE Child<>0 DO
     BEGIN
           WinSendMsg(NIL,NIL,WM_CLOSE,Child);
           {WinDestroyWindow(Child);}
           Child:=WinGetNextWindow(_HEnum);
     END;
     WinEndEnumWindows(_HEnum);
     ChildCount:=0;
     ActiveChild:=0;
END;

PROCEDURE TMDIApplication.HandleCommand(Win:HWND;command:WORD);
BEGIN
     Inherited.HandleCommand(Win,command);
     IF ChildCount>0 THEN
     BEGIN
          CASE command OF
             CM_CLOSE:WinSendMsg(NIL,NIL,WM_CLOSE,ActiveChild);
             CM_CASCADE:CascadeWindows;
             CM_TILE:TileWindows;
             CM_CLOSEALL:CloseAllWindows;
             CM_Next:NextWindow;
         END; {case}
     END;
END;

PROCEDURE TMDIApplication.WMClose(VAR Msg:TMessage);
BEGIN
     CloseAllWindows;
     Inherited.WMClose(Msg);
END;

PROCEDURE TMDIApplication.WMSize(VAR Msg:TMessage);
BEGIN
     Inherited.WMSize(Msg);
     {IF ChildCount>0 THEN TileWindows;}
END;

FUNCTION TMDIApplication.HandleEvent(Win:HWND;Msg:LONGWORD;
                             para1,para2:POINTER;
                             VAR Handled:BOOLEAN):LONGWORD;
VAR
    H:Boolean;
    _hps:HPS;
    r:LONGWORD;
    w,w1:WORD;
    b:WORD;
    ch:CHAR;
    rc:RECTL;
    command:WORD;
BEGIN
      r:=Inherited.HandleEvent(Win,msg,para1,para2,Handled);
      r:=0;
      IF not Handled THEN H:=FALSE;
      Handled:=H;
      HandleEvent:=r;
END;

PROCEDURE MDIMessageHandler(para2,para1:POINTER;Msg,Win:LONGWORD);ASM;
BEGIN
     ASM
        PUSH EBP
        MOV EBP,ESP
        SUB ESP,2
        ;Save parameters as it is SYSTEM Calling Convention
        PUSH EDI
        PUSH ESI
        PUSH EBX

        MOVW [EBP-2],0   ;Not Handled
        PUSHL $Win
        PUSHL $Msg
        PUSHL $para1
        PUSHL $para2
        LEA EAX,[EBP-2]
        PUSH EAX

        PUSHL 4             ;Get Extra pointer
        PUSHL $Win
        MOV AL,2
        CALLDLL PMWIN,843   ;QueryWindowUlong
        ADD ESP,8
        PUSH EAX            ;Extra

        PUSHL 0             ;Get VMT pointer
        PUSHL $Win
        MOV AL,2
        CALLDLL PMWIN,843   ;QueryWindowUlong
        ADD ESP,8
        MOV EDI,EAX
        PUSH EDI         ;VMT Pointer
        MOV EDI,[EDI+0]  ;get VMT pointer for MDIHandleEvent
        ADD EDI,4

        db ffh,17h       ;CALL NEAR32 [EDI+0] --> in Methode springen
        MOV BL,[EBP-2]
        CMP BL,0
        JNE !hh_1
        ;not handled
        ;Default Window handler
        PUSHL $para2
        PUSHL $para1
        PUSHL $msg
        PUSHL $win
        MOV AL,4
        CALLDLL PMWin,911   ;WinDefWindowProc
        ADD ESP,16
!hh_1:
        ;Get registers as it is SYSTEM calling convention
        POP EBX
        POP ESI
        POP EDI
        LEAVE
        RETN32
     END;
END;

FUNCTION TMDIApplication.GetMDIColor(Win:HWND):LONGINT;
BEGIN
     GetMDIColor:=WinQueryWindowULong(8,Win);
END;

FUNCTION TMDIApplication.GetMDIBackColor(Win:HWND):LONGINT;
BEGIN
     GetMDIBackColor:=WinQueryWindowULong(12,Win);
END;

PROCEDURE TMDIApplication.SetMDIColor(Win:HWND;col:LONGINT);
BEGIN
     WinSetWindowULong(col,8,Win);
END;

PROCEDURE TMDIApplication.SetMDIBackColor(Win:HWND;bcol:LONGINT);
BEGIN
     WinSetWindowULong(bcol,12,Win);
END;

PROCEDURE TMDIApplication.MDIRedraw(rc:RECTL;_hps:HPS;Win:HWND;
                                           Data:POINTER);
BEGIN
END;

PROCEDURE TMDIApplication.MDIHandleCommand(Win:HWND;command:WORD;Data:POINTER);
BEGIN
     HandleCommand(ClientHandle,command);
END;


PROCEDURE TMDIApplication.MDIHandleScanEvent(Win:HWND;scan:WORD;Data:POINTER);
BEGIN
END;

PROCEDURE TMDIApplication.MDIHandleCharEvent(Win:HWND;Ch:CHAR;Data:POINTER);
BEGIN
END;


PROCEDURE TMDIApplication.MDINoMoreChilds;
BEGIN
     SetMenuState(CM_TILE,FALSE);
     SetMenuState(CM_CASCADE,FALSE);
     SetMenuState(CM_CLOSE,FALSE);
     SetMenuState(CM_CLOSEALL,FALSE);
     SetMenuState(CM_NEXT,FALSE);
     SetMenuState(CM_LIST,FALSE);
END;

PROCEDURE TMDIApplication.MDIWMMouseMove(Win:HWND;x,y:INTEGER;Data:POINTER);
BEGIN
END;

PROCEDURE TMDIApplication.MDIWMButton1Click(Win:HWND;x,y:INTEGER;Data:POINTER);
BEGIN
END;

PROCEDURE TMDIApplication.MDIWMButton1DoubleClick(Win:HWND;x,y:INTEGER;Data:POINTER);
BEGIN
END;

PROCEDURE TMDIApplication.MDIWMButton1Down(Win:HWND;x,y:INTEGER;Data:POINTER);
BEGIN
END;


PROCEDURE TMDIApplication.MDIWMEraseBackGround(Win:HWND;rc:RECTL;_hps:HPS);
VAR bcol:INTEGER;
BEGIN
     bcol:=GetMDIBackColor(Win);
     WinFillRect(bcol,rc,_hps);
END;


PROCEDURE TMDIApplication.MDIWMButton1Up(Win:HWND;x,y:INTEGER;Data:POINTER);
BEGIN
END;

PROCEDURE TMDIApplication.MDIWMSize(Win:HWND;Data:POINTER);
BEGIN
END;


FUNCTION TMDIApplication.MDIHandleEvent(Win:HWND;Msg:LONGWORD;para1,
                                              para2:POINTER;VAR Handled:BOOLEAN;
                                              Data:POINTER):LONGWORD;
VAR
    H:Boolean;
    _hps:HPS;
    r:LONGWORD;
    bcol:LONGINT;
    command:WORD;
    rc:RECTL;
    _pswp:PSWP;
    Frame:HWND;
    w,w1:Word;
    b:WORD;
    ch:char;
    _swp:swp;
    po:POINTS;
Label l,l1,l3;
BEGIN
      r:=0;
      H:=TRUE;
      CASE Msg OF
          WM_SIZE:
          BEGIN
               MDIWMSize(Win,Data);
               IF not handled THEN h:=FALSE;
          END;
          WM_CHAR:
          BEGIN
               r:=LONGINT(para1);
               w:=lo(r);
               IF w AND $41=1 THEN {KC_CHAR valid and KC_KEYUP}
               BEGIN
                    r:=LONGINT(para2);
                    w1:=lo(r);
                    b:=lo(w1);
                    if b<32 THEN goto l;
                    IF w and $10=$10 THEN goto l; {KC_CTRL valid}
                    ch:=chr(b);
                    InCtrlK:=FALSE;
                    MDIHandleCharEvent(Win,ch,Data);
                    goto l1;
               END
               ELSE
               BEGIN
                    IF w AND $44=4 THEN {KC_CHAR valid and KC_KEYUP}
                    BEGIN
                         w1:=hi(r);
                         b:=hi(w1);
l:
                         IF w and $10=$10 THEN {Ctrl-Taste}
                         BEGIN
                              inc(b,256); {KC_CTRL valid}
                              CASE b OF
                                 kbCtrlK:
                                 BEGIN
                                     IF InCtrlK THEN goto l3;
                                     InCtrlK:=TRUE;
                                 END
                                 ELSE
                                 BEGIN
                                     IF InCtrlK THEN
                                     BEGIN
l3:
                                          inc(b,1000);
                                     END;
                                     InCtrlK:=FALSE;
                                 END;
                              END; {Case}
                         END
                         ELSE
                         BEGIN
                              InCtrlK:=FALSE;
                              IF w AND 8=8 THEN inc(b,512) {KC_SHIFT valid}
                              ELSE IF w AND $20=$20 THEN inc(b,768); {KC_ALT valid}
                         END;
                         MDIHandleScanEvent(Win,b,Data);
                         goto l1;
                    END;
               END;
          END;
          WM_COMMAND:
          BEGIN
               command:=PointerToWord(para1);
               MDIHandleCommand(Win,command,Data);
          END;
          WM_MINMAXFRAME:
          BEGIN
               {Minimize the window ??}
               _pswp:=para1;
               IF _pswp^.fl AND SWP_MINIMIZE<>0 THEN INC(MinimizedCount)
               ELSE
               BEGIN
                    Frame:=WinQueryWindow(QW_PARENT,Win);
                    IF IsWindowMinimized(Win) THEN
                    BEGIN
                         DEC(MinimizedCount);
                         WinSetWindowUShort(-1,QWS_XMINIMIZE,Frame);
                         WinSetWindowUShort(-1,QWS_YMINIMIZE,Frame);
                    END;
                    IF _pswp^.fl AND SWP_MAXIMIZE<>0 THEN
                    BEGIN
                         IF ((ToolBarSize>0)OR(StatusBarSize>0)OR
                            (LeftToolBarSize>0)OR(RightToolBarSize>0)) THEN
                         BEGIN
                              GetMaxDesktopWindow(_swp);
                              _pswp^.cx:=_swp.cx;
                              _pswp^.cy:=_swp.cy;
                              _pswp^.x:=_swp.x;
                              _pswp^.y:=_swp.y;
                         END;
                    END;
               END;
               IF not handled THEN H:=FALSE;
          END;
          WM_ACTIVATE:
          BEGIN
               ActiveChild:=Win;
          END;
          WM_CLOSE:WMMDIClose(Win,Data);
          WM_DESTROY:
          BEGIN
               IF IsWindowMinimized(Win) THEN dec(MinimizedCount);
               dec(ChildCount);
               IF ChildCount=0 THEN
               BEGIN
                    ActiveChild:=0;
                    MDINoMoreChilds; {No more windows available}
               END;
          END;
          WM_BUTTON1CLICK:
          BEGIN
               po:=POINTS(Para1);
               MDIWMButton1Click(Win,po.x,po.y,Data);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON1DBLCLK:
          BEGIN
               po:=POINTS(Para1);
               MDIWMButton1DoubleClick(Win,po.x,po.y,Data);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON1DOWN:
          BEGIN
               Drag_Mode:=FALSE;
               MouseButton1Down:=TRUE;
               po:=POINTS(para1);
               MDIWMButton1Down(Win,po.x,po.y,Data);
               IF not Handled THEN H:=FALSE;
          END;
          WM_BUTTON1UP:
          BEGIN
               MouseButton1Down:=FALSE;
               Drag_Mode:=FALSE;
               po:=POINTS(para1);
               MDIWMButton1Up(Win,po.x,po.y,Data);
               IF not Handled THEN H:=FALSE;
          END;
          WM_MOUSEMOVE:
          BEGIN
               IF MouseButton1Down THEN WinSendMsg(NIL,para1,WM_MOUSEDRAG1,Win);
               po:=POINTS(para1);
               MDIWMMouseMove(Win,po.x,po.y,Data);
          END;
          WM_ERASEBACKGROUND:
          BEGIN
               _hps:=WinBeginPaint(rc,0,Win);
               MDIWMEraseBackGround(Win,rc,_hps);
               MDIRedraw(rc,_hps,Win,Data);
               WinEndPaint(_hps);
               H:=FALSE;
          END;
          WM_PAINT:
          BEGIN
               _hps:=WinBeginPaint(rc,0,Win);
               MDIRedraw(rc,_hps,Win,Data);
               WinEndPaint(_hps);
          END;
          ELSE IF not Handled THEN H:=FALSE;
      END;
l1:
      Handled:=H;
      MDIHandleEvent:=r;
END;


PROCEDURE TMDIApplication.MDICreateNotify(MDIFrWin,MDIWin:HWND;Data:POINTER);
VAR
   _swp:SWP;
BEGIN
     GetMaxDesktopWindow(_swp);
     WinSetWindowPos(SWP_SPEED,_swp.cy,_swp.cx,_swp.y,_swp.x,0,MDIFrWin);
END;


PROCEDURE TMDIApplication.WMMDIClose(Win:HWND;Data:POINTER);
BEGIN
     WinDestroyWindow(WinQueryWindow(QW_PARENT,Win));
END;

FUNCTION TMDIApplication.CreateMDIChild(resid:LONGWORD;Title:String;
                                              Extra:POINTER;fcfFlags:LONGWORD;
                                              Col,BCol:LONGINT):HWND;
VAR HWndChild,ChildFrame:HWND;
    fr:LONGWORD;
    LastWin:HWND;
BEGIN
     IF ChildCount>=20 THEN
     BEGIN
          ErrorBox(MB_ICONHAND,'Too much child windows');
          CreateMDIChild:=0;
          exit;
     END;
     fr:=FCF_SPEEDCHILD or FCFFlags;
     LastWin:=ActiveChild;
     inc(ChildCount);
     SetMenuState(CM_TILE,TRUE);
     SetMenuState(CM_CASCADE,TRUE);
     SetMenuState(CM_CLOSE,TRUE);
     SetMenuState(CM_CLOSEALL,TRUE);
     SetMenuState(CM_NEXT,TRUE);
     SetMenuState(CM_LIST,TRUE);
     ChildFrame:=WinCreateStdWindow(DesktopClientHandle,0,fr,
                                    TMDIWindowClass,Title,0,0,ResID,
                                    hwndChild);
     WinSetWindowULong(LONGWORD(SELF),0,hwndChild); {VMT pointer}
     WinSetWindowULong(LONGWORD(Extra),4,hwndChild);
     WinSetWindowULong(Col,8,hwndChild);
     WinSetWindowULong(BCol,12,hwndChild);
     WinSubClassWindow(@MDIMessageHandler,hwndChild);

     IF ActiveChild<>0 THEN IF IsWindowMaximized(ActiveChild) THEN
      RestoreWindow(WinQueryWindow(QW_PARENT,ActiveChild));
     WinSetOwner(ChildFrame,hwndChild);

     MDICreateNotify(ChildFrame,hwndChild,Extra);
     CreateMDIChild:=ChildFrame;
END;

FUNCTION TMDIApplication.MDIGetDataPointer(Win:HWND):POINTER;
VAr Result:POINTER;
BEGIN
    ASM
       PUSHL 4
       PUSHL $Win
       MOV AL,2
       CALLDLL PMWIN,843   ;WinQueryWindowUlong
       ADD ESP,8
       MOV $Result,EAX
    END;
    MDIGetDataPointer:=result;
END;

FUNCTION TMDIApplication.MDIGetTopWindow(VAR Extra:POINTER):HWND;
VAR Win:HWND;
BEGIN
     Win:=ActiveChild;
     IF Win<>0 THEN Extra:=MDIGetDataPointer(Win)
     ELSE Extra:=NIL;
     MDIGetTopWindow:=Win;
END;

PROCEDURE TMDIApplication.MDIBringToTop(Win:HWND);
BEGIN
     WinSetWindowPos(SWP_ZORDER or SWP_ACTIVATE,0,0,0,0,HWND_TOP,Win);
END;


{*************************************************************************
*                                                                        *
*                              MAIN                                      *
*                                                                        *
**************************************************************************}





BEGIN
     TWindowClass:='OPMWindowClass';
     WinRegisterClass(AppHandle,TWindowClass,@StartHandler,
                      CS_SIZEREDRAW,4);
     TDesktopWindowClass:='OPMDesktopWindowClass';
     WinRegisterClass(AppHandle,TDesktopWindowClass,@StartHandler,
                      CS_SIZEREDRAW,4);
     TMDIWindowClass:='OPMMDIWindowClass';
     WinRegisterClass(AppHandle,TMDIWindowClass,@StartHandler,
                      CS_SIZEREDRAW,16);
END.