PROGRAM MineHelp;

  {Version 1.00: April 26, 1992.
   Version 1.01: May 8, 1993.
   Version 1.02: May 29, 1993.
   Peter Karrer (pkarrer@bernina.ethz.ch / 100121,2215)}

  {$M 40960,8192}
  {$G+}

  USES WObjects, WinTypes, WinProcs, Strings;

  {$R MINEHELP.RES}

  CONST
    appName = 'MineHelp';
    {Child control IDs}
    inactive = 103;
    active = 104;
    automatic = 105;
    basic = 106;
    expert = 107;
    rand = 108;
    id_Animation = 110;
    id_OK = 109;

    white = $ffffff;
    {colors masked with $ffc0c0c0}
    blue  = $c00000;
    dblue = $800000;
    red   = $0000c0;
    dred  = $000080;
    dgreen= $008000;
    dcyan = $808000;
    black = 0;
    dgray = $808080;
    gray  = $c0c0c0;
    xOff = -4; { width of left border in Minesweeper window client area - 16}
    yOff = 39; { width of top  border in Minesweeper window client area - 16}

  TYPE

    TThisApp = OBJECT(TApplication)
      PROCEDURE InitMainWindow; VIRTUAL;
    END;

    PThisWindow = ^TThisWindow;
    TThisWindow = OBJECT(TDlgWindow)
      stat: INTEGER; {id of checked "Status" button}
      lev: INTEGER;  {id of checked "Level" button}
      animation: BOOLEAN;
      msWin: HWnd;
      mswX, mswY: INTEGER;
      dimX, dimY: INTEGER;
      busy: BOOLEAN;
      CONSTRUCTOR Init;
      FUNCTION  GetClassName: PCHAR; VIRTUAL;
      PROCEDURE GetWindowClass(VAR c: TWndClass); VIRTUAL;
      PROCEDURE SetupWindow; VIRTUAL;
      PROCEDURE DefChildProc(VAR msg: TMessage); VIRTUAL;
      PROCEDURE WMDestroy(VAR msg: TMessage); VIRTUAL wm_first + wm_Destroy;
      PROCEDURE WMTimer(VAR msg: TMessage); VIRTUAL wm_first + wm_Timer;
      PROCEDURE DoIt;
      FUNCTION  GetMsWin: HWnd;
      PROCEDURE GetBoard(VAR bomb: BOOLEAN);
      PROCEDURE Click(x, y: INTEGER; btnDown, btnUp, modifier: WORD);
      PROCEDURE Mark(x, y: INTEGER);
      PROCEDURE ClearFields(VAR somethingDone: BOOLEAN);
      PROCEDURE MarkFields(VAR somethingDone: BOOLEAN);
      FUNCTION  TwoFieldSearch(x1, y1, x2, y2: INTEGER): BOOLEAN;
      PROCEDURE TwoFields(VAR success: BOOLEAN);
      PROCEDURE ClearRandom(VAR somethingHappened: BOOLEAN);
    END;

  VAR
    thisApp: TThisApp;
    bb: ARRAY [0..25, 0..31] OF INTEGER;
    ee: ARRAY [0..25, 0..31] OF INTEGER;

  CONSTRUCTOR TThisWindow.Init;
  BEGIN
    TDlgWindow.Init(NIL, appName);
  END;

  FUNCTION TThisWindow.GetClassName: PCHAR;
  BEGIN
    GetClassName := appName;
  END;

  PROCEDURE TThisWindow.GetWindowClass(VAR c: TWndClass);
  BEGIN
    TDlgWindow.GetWindowClass(c);
    {c.hIcon := LoadIcon(hInstance, appName); doesn't work?!}
  END;

  PROCEDURE TThisWindow.SetupWindow;
    VAR
      i: INTEGER;
  BEGIN
    TDlgWindow.SetupWindow;
    IF SetTimer(hWindow, 1, 1000, NIL) = 0 THEN BEGIN
      MessageBox(HWindow, 'Sorry, no timers', NIL, mb_Ok);
      Destroy;
    END;
    {Setting the icon didn't work in GetWindowClass, dunno why}
    SetClassWord(hWindow, GCW_HICON, LoadIcon(hInstance, appName));
    animation := POS('n', ParamStr(1)) <> 0;
    IF POS('h', ParamStr(1)) <> 0 THEN BEGIN
      cmdShow := sw_Hide;
    END ELSE IF POS('c', ParamStr(1)) <> 0 THEN BEGIN
      cmdShow := sw_Minimize;
    END;
    IF POS('a', ParamStr(1)) <> 0 THEN BEGIN
      stat := active;
    END ELSE IF POS('i', ParamStr(1)) <> 0 THEN BEGIN
      stat := inactive;
    END ELSE BEGIN
      stat := automatic;
    END;
    IF POS('b', ParamStr(1)) <> 0 THEN BEGIN
      lev := basic;
    END ELSE IF POS('r', ParamStr(1)) <> 0 THEN BEGIN
      lev := rand;
    END ELSE BEGIN
      lev := expert;
    END;
    SendDlgItemMsg(stat, bm_SetCheck, 1, 0);
    SendDlgItemMsg(lev, bm_SetCheck, 1, 0);
    SendDlgItemMsg(id_animation, bm_SetCheck, ORD(animation), 0);
    RANDOMIZE;
    busy := FALSE;
  END;

  PROCEDURE WaitIdle;
    {It's impolite to hog the CPU}
    VAR
      m: TMsg;
  BEGIN
    WHILE PeekMessage(m, 0, 0, 0, pm_Remove) DO BEGIN
      IF m.message = wm_Quit THEN BEGIN
        HALT(m.wParam);
      END;
      TranslateMessage(m);
      DispatchMessage(m);
    END;
  END;

  PROCEDURE TThisWindow.Click(x, y: INTEGER; btnDown, btnUp, modifier: WORD);
  BEGIN
    IF animation THEN BEGIN
      SetCursorPos(mswX + xOff + 16*x + 8, mswY + yOff + 16*y + 8);
    END;
    SendMessage(msWin, btnDown, modifier, MakeLong(xOff + 16*x, yOff + 16*y));
    SendMessage(msWin, btnUp, modifier, MakeLong(xOff + 16*x, yOff + 16*y));
  END; {Click}

  PROCEDURE TThisWindow.GetBoard(VAR bomb: BOOLEAN);
    {Examine the Minesweeper window client area. Get the contents of the
     individual squares by reading pixels at strategic locations. Colors
     are masked with $FFC0C0C0, because not all display drivers use the same
     intensities for colors like dark cyan or dark red}
    VAR
      x, y, v: INTEGER;
      rgb: LONGINT;
      msDC: HDC;
  BEGIN
    bomb := FALSE;
    msDC := GetDC(msWin);
    FOR y := 1 TO dimY DO BEGIN
      FOR x := 1 TO dimX DO BEGIN
        rgb := GetPixel(msDC, xOff + 9 + 16*x, yOff + 12 + 16*y) AND $ffc0c0c0;
        IF rgb = blue THEN BEGIN
          bb[y, x] := 1;
        END ELSE IF rgb = dgreen THEN BEGIN
          bb[y, x] := 2;
        END ELSE IF rgb = red THEN BEGIN
          bb[y, x] := 3;
        END ELSE IF rgb = dblue THEN BEGIN
          bb[y, x] := 4;
        END ELSE IF rgb = dred THEN BEGIN
          bb[y, x] := 5;
        END ELSE IF rgb = dcyan THEN BEGIN
          bb[y, x] := 6;
        END ELSE IF rgb = black THEN BEGIN
          rgb := GetPixel(msDC, xOff + 7 + 16*x, yOff + 6 + 16*y);
          IF rgb = white THEN BEGIN
            bb[y, x] := -2; bomb := TRUE; {mine}
          END ELSE BEGIN
            rgb := rgb AND $ffc0c0c0;
            IF rgb = gray THEN BEGIN
              bb[y, x] := 7;
            END ELSE IF rgb = red THEN BEGIN
              bb[y, x] := 128; {flag}
            END ELSE IF rgb = black THEN BEGIN
              bb[y, x] := 2049; {question mark}
            END ELSE BEGIN
              bb[y, x] := -999; bomb := TRUE; {invisible}
            END;
          END;
        END ELSE IF rgb = dgray THEN BEGIN
          bb[y, x] := 8;
        END ELSE IF rgb = gray THEN BEGIN
          rgb := GetPixel(msDC, xOff + 15 + 16*x, yOff + 1 +16*y) AND $ffc0c0c0;
          IF rgb = gray THEN BEGIN
            bb[y, x] := 0;
          END ELSE IF rgb = dgray THEN BEGIN
            rgb := GetPixel(msDC, xOff + 5 + 16*x, yOff + 5 +16*y) AND $ffc0c0c0;
            IF rgb = black THEN BEGIN
              bb[y,x] := 2049; {question mark}
            END ELSE IF rgb = gray THEN BEGIN
              bb[y, x] := 2048; {covered}
            END ELSE BEGIN
              bb[y, x] := -999; bomb := TRUE;
            END;
          END ELSE BEGIN
            bb[y, x] := -999; bomb := TRUE; {invisible}
          END;
        END ELSE BEGIN
          bb[y, x] := -999; bomb := TRUE; {invisible}
        END;
      END; {FOR x}
    END; {FOR y}
    ReleaseDC(msWin, msDC);
    IF NOT bomb THEN BEGIN
      FOR y := 1 TO dimY DO BEGIN
        FOR x := 1 TO dimX DO BEGIN
          v := bb[y, x];
          IF (v > 0) AND (v <= 8) THEN BEGIN
            ee[y, x] := bb[y-1,x-1]+bb[y-1,x]+bb[y-1,x+1]+bb[y,x-1]+
                        bb[y,x+1]+bb[y+1,x-1]+bb[y+1,x]+bb[y+1,x+1];
          END ELSE BEGIN
            ee[y, x] := 0;
          END;
        END; {FOR x}
      END; {FOR y}
    END; {NOT bomb}
  END; {GetBoard}

  FUNCTION TThisWindow.GetMsWin: HWnd;
    {Find the Minesweeper window and its location on the screen}
    VAR
      w, mW: HWnd;
      st: ARRAY[0..32] OF CHAR;
      rp: RECORD
            CASE INTEGER OF 1: (r: TRect);
                            2: (p: TPoint);
          END;
      i: INTEGER;
  BEGIN
    w := 0;
    mW := 0;
    w := GetWindow(hWindow, gw_HWndFirst);
    WHILE (w <> 0) AND (mW = 0) DO BEGIN
      WinProcs.GetClassName(w, st, 32); {v1.02}
      IF StrComp(st, 'Minesweeper') = 0 THEN BEGIN
        mW := w;
        GetClientRect(mW, rp.r);
        dimX := (rp.r.right - 24) DIV 16;
        dimY := (rp.r.bottom - 67) DIV 16;
        ClientToScreen(mW, rp.p);
        mswX := rp.p.x;
        mswY := rp.p.y;
      END;
      w := GetNextWindow(w, gw_HWndNext);
    END;
    IF mW <> 0 THEN BEGIN
      FOR i := 0 TO dimX + 1 DO BEGIN
        bb[0, i] := 0;
        ee[0, i] := 0;
        bb[dimY + 1, i] := 0;
        ee[dimY + 1, i] := 0;
      END;
      FOR i:= 1 TO dimY DO BEGIN
        bb[i, 0] := 0;
        ee[i, 0] := 0;
        bb[i, dimX + 1] := 0;
        ee[i, dimX + 1] := 0;
      END;
    END;
    GetMsWin := mW;
  END; {GetMsWin}

  PROCEDURE TThisWindow.ClearFields(VAR somethingDone: BOOLEAN);
    VAR
      x, y, v, c: INTEGER;
  BEGIN
    somethingDone := FALSE;
    FOR y := 1 TO dimY DO BEGIN
      FOR x := 1 TO dimX DO BEGIN
        v := bb[y, x];
        IF (v > 0) AND (v <= 8) THEN BEGIN
          c := ee[y, x];
          IF c >= 2048 THEN BEGIN {at least 1 covered field}
            c := c AND 2047 SHR 7; {number of flagged fields}
            IF v = c THEN BEGIN
              Click(x, y, wm_LButtonDown, wm_LButtonUp, mk_RButton);
              somethingDone := TRUE;
              IF stat <> automatic THEN BEGIN
                EXIT;
              END;
            END;
          END;
        END; {IF (v > 0) ..}
      END; {FOR x}
    END; {FOR y}
  END; {ClearFields}

  PROCEDURE TThisWindow.Mark(x, y: INTEGER);
  BEGIN
    Click(x, y, wm_RButtonDown, wm_RButtonUp, 0);
    IF bb[y, x] = 2049 THEN BEGIN {question mark}
      Click(x, y, wm_RButtonDown, wm_RButtonUp, 0);
    END;
    bb[y, x] := 128; {make it flagged}
  END; {Mark}

  PROCEDURE TThisWindow.MarkFields(VAR somethingDone: BOOLEAN);
    VAR
      x, y, v, c, f: INTEGER;
  BEGIN
    somethingDone := FALSE;
    FOR y := 1 TO dimY DO BEGIN
      FOR x := 1 TO dimX DO BEGIN
        v := bb[y, x];
        IF (v > 0) AND (v <= 8) THEN BEGIN
          c := bb[y-1,x-1]+bb[y-1,x]+bb[y-1,x+1]+bb[y,x-1]+
               bb[y,x+1]+bb[y+1,x-1]+bb[y+1,x]+bb[y+1,x+1];
          f := c SHR 11; {number of covered fields}
          IF f <> 0 THEN BEGIN
            c := c AND 2047 SHR 7; {number of flagged fields}
            IF (f + c) = v THEN BEGIN
              IF bb[y-1,x-1] >= 2048 THEN BEGIN Mark(x-1,y-1); END;
              IF bb[y-1,x  ] >= 2048 THEN BEGIN Mark(x,  y-1); END;
              IF bb[y-1,x+1] >= 2048 THEN BEGIN Mark(x+1,y-1); END;
              IF bb[y,  x-1] >= 2048 THEN BEGIN Mark(x-1,y  ); END;
              IF bb[y,  x+1] >= 2048 THEN BEGIN Mark(x+1,y  ); END;
              IF bb[y+1,x-1] >= 2048 THEN BEGIN Mark(x-1,y+1); END;
              IF bb[y+1,x  ] >= 2048 THEN BEGIN Mark(x,  y+1); END;
              IF bb[y+1,x+1] >= 2048 THEN BEGIN Mark(x+1,y+1); END;
              somethingDone := TRUE;
              IF stat <> automatic THEN BEGIN
                EXIT;
              END;
            END;
          END;
        END; {IF (v > 0) ..}
      END; {FOR x}
    END; {FOR y}
  END; {MarkFields}

  FUNCTION TThisWindow.TwoFieldSearch(x1, y1, x2, y2: INTEGER): BOOLEAN;
    VAR
      a, b, c, x, y, na, nb: INTEGER;

    PROCEDURE ClickFields(xx1, yy1, xx2, yy2: INTEGER; marks: BOOLEAN);
      {Click on covered fields in environment of (x1,y1) but not of (x2,y2)}
      VAR
        xx, yy, dbg: INTEGER;
    BEGIN
      FOR yy := yy1 - 1 TO yy1 + 1 DO BEGIN
        FOR xx := xx1 - 1 TO xx1 + 1 DO BEGIN
          IF ((ABS(yy-yy2) > 1) OR (ABS(xx-xx2) > 1)) AND (bb[yy,xx] >= 2048) THEN BEGIN
            IF marks THEN BEGIN
              Mark(xx, yy);
            END ELSE BEGIN
              Click(xx, yy, wm_LButtonDown, wm_LButtonUp, 0);
              bb[yy, xx] := 0; {meaning uncovered with unknown value}
            END;
          END;
        END; {FOR xx}
      END; {FOR yy}
      TwoFieldSearch := TRUE;
    END; {ClickFields}

  BEGIN {TwoFieldSearch}
    TwoFieldSearch := FALSE;
    c := ee[y1, x1];
    x := bb[y1, x1] - c AND 2047 SHR 7; {Number of unknown mines around A=(x1,y1)}
    a := c SHR 11; {Number of covered fields around A=(x1,y1)}
    c := ee[y2, x2];
    y := bb[y2, x2] - c AND 2047 SHR 7; {Number of unknown mines around B=(x2,y2)}
    b := c SHR 11; {Number of covered fields around B=(x2,y2)}
    c := 0;
    IF (ABS(y1+1-y2) <=1) AND (ABS(x1-x2) <= 1) AND (bb[y1+1,x1] >= 2048) THEN c := c + 1;
    IF (ABS(y1+1-y2) <=1) AND (ABS(x1+1-x2)<=1) AND (bb[y1+1,x1+1]>=2048) THEN c := c + 1;
    IF (ABS(y1+1-y2) <=1) AND (ABS(x1-1-x2)<=1) AND (bb[y1+1,x1-1]>=2048) THEN c := c + 1;
    IF (ABS(y1-y2) <= 1) AND (ABS(x1+1-x2)<= 1) AND (bb[y1,x1+1] >= 2048) THEN c := c + 1;
    IF (ABS(y1-y2) <= 1) AND (ABS(x1-1-x2)<= 1) AND (bb[y1,x1-1] >= 2048) THEN c := c + 1;
    IF (ABS(y1-1-y2) <=1) AND (ABS(x1-x2) <= 1) AND (bb[y1-1,x1] >= 2048) THEN c := c + 1;
    IF (ABS(y1-1-y2) <=1) AND (ABS(x1+1-x2)<=1) AND (bb[y1-1,x1+1]>=2048) THEN c := c + 1;
    IF (ABS(y1-1-y2) <=1) AND (ABS(x1-1-x2)<=1) AND (bb[y1-1,x1-1]>=2048) THEN c := c + 1;
    {c = number of covered fields common to the environments of A and B}
    IF c < 2 THEN BEGIN {v1.01}
      EXIT;             {v1.01}
    END;                {v1.01}
    a := a - c;
    b := b - c;
    na := -1;
    nb := -1;
    IF a = 0 THEN BEGIN
      na := 0;
    END ELSE IF x + b = y THEN BEGIN
      na := 0;
    END ELSE IF x - a = y THEN BEGIN
      na := a;
    END ELSE IF b = 0 THEN BEGIN
      na := x - y;
    END;
    IF na >= 0 THEN BEGIN
      nb := y - x + na;
    END ELSE IF b = 0 THEN BEGIN
      nb := 0;
    END ELSE IF y - b = x THEN BEGIN
      nb := b;
    END ELSE IF a = 0 THEN BEGIN
      nb := y - x;
    END;
    IF nb >= 0 THEN BEGIN
      na := x - y + nb;
    END;
    IF a <> 0 THEN BEGIN
      IF na = 0 THEN BEGIN
        {Clear all fields in env A but not env B}
        ClickFields(x1, y1, x2, y2, FALSE);
      END ELSE IF na = a THEN BEGIN
        {Mark all those fields}
        ClickFields(x1, y1, x2, y2, TRUE);
      END;
    END;
    IF b <> 0 THEN BEGIN
      IF (nb = 0) AND (b <> 0) THEN BEGIN
        {Clear all fields in env B but not env A}
        ClickFields(x2, y2, x1, y1, FALSE);
      END ELSE IF nb = b THEN BEGIN
        {Mark all those fields}
        ClickFields(x2, y2, x1, y1, TRUE);
      END;
    END;
  END; {TwoFieldSearch}

  PROCEDURE TThisWindow.TwoFields(VAR success: BOOLEAN);

    PROCEDURE S(x1, y1: INTEGER);
      VAR
        x, y, miny, maxy: INTEGER;
    BEGIN
      IF success AND (stat <> automatic) THEN BEGIN
        EXIT;
      END;
      IF y1 >= 0 THEN BEGIN
        miny := 1;
        maxy := dimY - y1;
      END ELSE BEGIN
        miny := 1 - y1;
        maxy := dimY;
      END;
      FOR y := miny TO maxy DO BEGIN
        FOR x := 1 TO dimX - x1 DO BEGIN
          IF (ee[y, x] >= 2048) AND (ee[y + y1, x + x1] >= 2048) THEN BEGIN
            success := success OR TwoFieldSearch(x, y, x + x1, y + y1);
            IF success AND (stat <> automatic) THEN BEGIN
              EXIT;
            END;
          END;
        END;
      END;
    END; {S}

  BEGIN {TwoFields}
    success := FALSE;
    S(1, 0); S(0, -1); S(1, 1); S(1, -1); S(2, -1); S(2, 1);
    S(1, -2); S(1, 2); S(2, 0); S(0, -2); {S(2, -2); S(2, 2); v1.01}
  END; {TwoFields}

  PROCEDURE TThisWindow.ClearRandom(VAR somethingHappened: BOOLEAN);
    VAR
      x, y, c, i: INTEGER;
      bomb: BOOLEAN;
  BEGIN
    GetBoard(bomb);
    somethingHappened := FALSE;
    IF NOT bomb THEN BEGIN
      c := 0;
      FOR y := 1 TO dimY DO BEGIN
        FOR x:= 1 TO dimX DO BEGIN
          IF bb[y, x] >= 2048 THEN BEGIN
            c := c + 1;
          END;
        END;
      END;
      IF c <> 0 THEN BEGIN
        i := RANDOM(c);
        c := 0;
        FOR y := 1 TO dimY DO BEGIN
          FOR x := 1 TO dimX DO BEGIN
            IF bb[y, x] >= 2048 THEN BEGIN
              IF c = i THEN BEGIN
                Click(x, y, wm_LButtonDown, wm_LButtonUp, 0);
                somethingHappened := TRUE;
                EXIT;
              END;
              c := c + 1;
            END;
          END; {FOR x}
        END; {FOR y}
      END; {c <> 0}
    END; {NOT bomb}
  END; {ClearRandom}

  PROCEDURE TThisWindow.DefChildProc(VAR msg: TMessage);
    VAR
      i: INTEGER;
  BEGIN
    WITH msg DO BEGIN
      IF (lParamLo <> 0) AND (lParamHi <> 1) THEN BEGIN
        { not menu, not accelerator id }
        IF wParam = inactive THEN BEGIN
          stat := inactive;
        END ELSE IF wParam = active THEN BEGIN
          stat := active;
        END ELSE IF wParam = automatic THEN BEGIN
          stat := automatic;
        END ELSE IF wParam = basic THEN BEGIN
          lev := basic;
        END ELSE IF wParam = expert THEN BEGIN
          lev := expert;
        END ELSE IF wParam = rand THEN BEGIN
          lev := rand;
        END ELSE IF wParam = id_Animation THEN BEGIN
          animation := NOT animation;
          SendDlgItemMsg(id_Animation, bm_SetCheck, ORD(animation), 0);
        END ELSE IF wParam = id_OK THEN BEGIN
          IF stat = active THEN BEGIN
            DoIt;
          END;
        END;
      END; {IF (lParamLo ..}
    END; {WITH msg}
    TDlgWindow.DefChildProc(msg);
  END;

  PROCEDURE TThisWindow.DoIt;
    VAR
      bomb, somethingHappened, action: BOOLEAN;
      x, y: INTEGER;
      m: TMsg;
  BEGIN
    IF busy THEN BEGIN
      {avoid reentrancy}
      EXIT;
    END;
    busy := TRUE;
    msWin := GetMsWin;
    IF msWin <> 0 THEN BEGIN
     REPEAT
      REPEAT
        GetBoard(bomb);
        action := FALSE;
        somethingHappened := TRUE;
        WHILE NOT bomb AND somethingHappened DO BEGIN
          MarkFields(somethingHappened);
          IF somethingHappened AND (stat <> automatic) THEN BEGIN
            busy := FALSE;
            EXIT;
          END;
          WaitIdle;
          action := action OR somethingHappened;
          {GetBoard(msWin, bomb);}
        END;
        somethingHappened := TRUE;
        WHILE NOT bomb AND somethingHappened DO BEGIN
          ClearFields(somethingHappened);
          IF somethingHappened AND (stat <> automatic) THEN BEGIN
            busy := FALSE;
            EXIT;
          END;
          WaitIdle;
          action := action OR somethingHappened;
          GetBoard(bomb);
        END;
        {action = there were changes in mark and clear phases}
      UNTIL NOT action OR bomb;
      somethingHappened := lev > basic;
      WHILE NOT bomb AND somethingHappened DO BEGIN
        TwoFields(somethingHappened);
        IF somethingHappened AND (stat <> automatic) THEN BEGIN
          busy := FALSE;
          EXIT;
        END;
        WaitIdle;
        action := action OR somethingHappened;
        GetBoard(bomb);
      END;
      IF (lev = rand) AND NOT action THEN BEGIN
        ClearRandom(action);
        IF stat <> automatic THEN BEGIN
          busy := FALSE;
          EXIT;
        END;
      END;
     UNTIL NOT action OR bomb;
    END; {msWin <> 0}
    busy := FALSE;
  END; {DoIt}

  PROCEDURE TThisWindow.WMTimer(VAR msg: TMessage);
  BEGIN
    IF stat = automatic THEN BEGIN
      DoIt;
    END;
  END;

  PROCEDURE TThisWindow.WMDestroy(VAR msg: TMessage);
  BEGIN
    KillTimer(hWindow, 1);
    TDlgWindow.WMDestroy(msg);
  END;

  PROCEDURE TThisApp.InitMainWindow;
  begin
    mainWindow := NEW(PThisWindow, Init);
  end;

BEGIN
  {$G-}
  IF (GetWinFlags AND (wf_CPU086 OR wf_CPU186)) <> 0 THEN BEGIN
    MessageBox(0, 'WinHelp needs a 286 or better', NIL, mb_OK);
    HALT(0);
  END;
  {$G+}
  thisApp.Init(appName);
  thisApp.Run;
  thisApp.Done;
END.
