Unit WinUtils;
Interface

Uses
  Windows,
  Messages,
  GraphUtils;

TYPE
  TWinProc = Function (wnd : HWnd; msg : Cardinal; wParam, lParam : Longint) : LResult; stdcall;

  //========================//

  TMyWindow = Class

    protected

      HWND                : HWnd;
      WndClass            : TWndClass;
      WindowName          : PChar;
      WndX,WndY,WndW,WndH : Longint;
      FS                  : LongBool;

    private

      Function Init : HWnd; Virtual;

    public

      Property GetWindowHandle : HWnd Read HWND;

      Constructor Create(X,Y,W,H : Longint; FullScreen : Longbool = false); Virtual;
      Destructor Destroy; Override;
      Procedure Free; Virtual;

      Procedure Draw; Virtual;

  end;

  //========================//

  TMyForm = Class(TMyWindow)

    protected

    private
      Game : TGame;

      Function Init : HWnd; Override;

    public
      Property GetGame : TGame Read Game;

      Procedure Free; Override;

  end;

  //========================//

  TMyApplication = Class

    protected

      Game : TGame;

      ExitApplication : LongBool;
      WindowCounter   : Longint; //счётчик созданных окон

    private

    public

      Constructor Create; Virtual;
      Destructor Destroy; Override;
      Procedure Free; Virtual;
      Procedure Run;

      Procedure IncWindowCounter;
      Procedure DecWindowCounter;
      Procedure CheckExitApplication;

      Function CreateWindow(X,Y,W,H : Longint; FullScreen : LongBool = False) : TMyForm;

  end;

  //========================//


Var
  Application : TMyApplication = nil;

Implementation

Function DefaultWndProc(wnd : HWnd; msg : Cardinal; wParam, lParam : Longint) : LResult; stdcall;
begin
  Result:=0;
  case msg of

  WM_PAINT :
    begin
     ValidateRect(WND,nil);
    end; //WM_PAINT

  WM_CREATE :
    begin
      //Увеличение счётчика созданных окон:
      if Application<>nil then Application.IncWindowCounter;
    end;

  WM_CLOSE :
    begin
      DestroyWindow(wnd);
    end; //WM_CLOSE

  WM_DESTROY :
    begin
      if Application<>nil then
      begin
        //Уменьшение счётчика созданных окон:
        Application.DecWindowCounter;
        //Проверка, если созданных окон не осталось, то выходим из программы:
        Application.CheckExitApplication;
      end;
      PostQuitMessage(0);
    end; //WM_DESTROY

  ELSE Result:=DefWindowProc(wnd, msg, wParam, lParam);

  end; //case msg
end;


//========= TMyWindow ========================================================//

Constructor TMyWindow.Create(X,Y,W,H : Longint; FullScreen : Longbool = false);
begin
  Inherited Create;
  WndX := X;
  WndY := Y;
  WndW := W;
  WndH := H;
  FS:=FullScreen;

  FillChar(WndClass,SizeOf(WndClass),$00);
  WindowName := 'TMyWindow';
  HWND:=Init; //Handle of the created window

end;

Destructor TMyWindow.Destroy;
begin
  Inherited;
end;

Function TMyWindow.Init : HWnd;
begin
  Result := 0;
end;

Procedure TMyWindow.Free;
begin
  Inherited;
end;

Procedure TMyWindow.Draw;
begin
  ValidateRect(HWND,nil);
end;

//========= TMyForm   ========================================================//

Function TMyForm.Init : HWnd;
Var
  Flags : Cardinal;
begin
  Result:=Inherited Init;

  WndClass.style := CS_CLASSDC; //флаг CS_NOCLOSE - не закрывать окно по нажатию Alt+F4

  WndClass.lpfnWndProc := @DefaultWndProc;
  WndClass.cbClsExtra := 0;
  WndClass.cbWndExtra := 0;
  WndClass.hInstance := hInstance;
  WndClass.hIcon := 0;//LoadIcon ( 0,'');
  WndClass.hCursor := LoadCursor(0,idc_arrow);
  WndClass.hbrBackground := (COLOR_WINDOW + 1);//GetStockObject(NULL_BRUSH);
  WndClass.lpszMenuName := nil;
  WndClass.lpszClassName := 'TMyWindowClass';
  if not Boolean(Windows.RegisterClass(WndClass)) then begin {Beep(1000,100); Exit;} end;

  Flags:=WS_MINIMIZEBOX or WS_VISIBLE;
  if FS then Flags:=Flags or WS_POPUP;

  Result:=CreateWindowEx(
    0,//WS_EX_APPWINDOW,
    WndClass.lpszClassName,
    WindowName,
    WS_SYSMENU or
    Flags,
    WndX,
    WndY,
    WndW,
    WndH,
    0,//GetDesktopWindow,
    0,
    hInstance,
    Nil);

  Game:=Nil;
  if Result<>0 then
  begin
    Game:=TGame.Create(WndW,WndH,FS,False,True,0,Result);
    if (Game.GetLastError>0) then Beep(1000,100);
  end;

  ShowCursor(False);

end;

Procedure TMyForm.Free;
begin
  ShowCursor(True);

  if Game<>nil then
  begin
    Game.Free;
    Game:=nil;
  end;

  if HWND<>0 then Windows.CloseWindow(HWND);
  Windows.UnRegisterClass(WndClass.lpszClassName, hInstance);
  Inherited;
end;

//========= TMyApplication   =================================================//

Constructor TMyApplication.Create;
begin
  Inherited;
  ExitApplication := False;
  WindowCounter   := 0;
  Game:=nil;
end;

Destructor TMyApplication.Destroy;
begin
  Inherited;
end;

Procedure TMyApplication.Free;
begin
  Inherited;
end;

Procedure TMyApplication.Run;
Var
  Mesg     : TMsg;
begin

  Repeat

    if Assigned(Game) then Game.Process else WaitMessage;

    while PeekMessage(Mesg,0,0,0,PM_REMOVE) do
    begin
      TranslateMessage(Mesg);
      DispatchMessage(Mesg);
    end;

  Until ExitApplication;

  Free;
  
end;

Function TMyApplication.CreateWindow(X,Y,W,H : Longint; FullScreen : LongBool = False) : TMyForm ;
begin
  Result:=TMyForm.Create(X,Y,W,H,FullScreen);
  Game:=Result.GetGame;
end;

Procedure TMyApplication.IncWindowCounter;
begin
  Inc(WindowCounter);
end;

Procedure TMyApplication.DecWindowCounter;
begin
  Dec(WindowCounter);
end;

Procedure TMyApplication.CheckExitApplication;
begin
  ExitApplication:=WindowCounter<=0;
end;

//============================================================================//

Initialization

  Application := TMyApplication.Create;
  if Application=nil then
  begin
    Beep(1000,100);
    Halt(1);
  end;

Finalization

end.
