home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tolkit45.zip / os2tk45 / samples / os2 / npipe / clnpmain.c < prev    next >
C/C++ Source or Header  |  1999-05-11  |  25KB  |  822 lines

  1. /*==============================================================*\
  2.  *  clnpmain.c - Pipe Server end of Tic-Tac-Toe sample app
  3.  *      Copyright 1992 IBM Corp.
  4.  *--------------------------------------------------------------
  5.  *
  6.  *  DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
  7.  *  sample code created by IBM Corporation. This sample code is not
  8.  *  part of any standard or IBM product and is provided to you solely
  9.  *  for  the purpose of assisting you in the development of your
  10.  *  applications.  The code is provided "AS IS", without
  11.  *  warranty of any kind.  IBM shall not be liable for any damages
  12.  *  arising out of your use of the sample code, even if they have been
  13.  *  advised of the possibility of   such damages.                                                     *
  14.  *
  15.  *--------------------------------------------------------------
  16.  *
  17.  *  This c file contains the window creation routines and
  18.  *  manages the PM message queue.
  19.  *
  20. \*==============================================================*/
  21.  
  22.  
  23.  
  24. /*--------------------------------------------------------------*\
  25.  *  Include files, macros, defined constants, and externs
  26. \*--------------------------------------------------------------*/
  27. #define INCL_WINHELP
  28. #define INCL_DOSPROCESS
  29. #define INCL_WINMESSAGEMGR
  30. #define INCL_WINWINDOWMGR
  31. #define INCL_WININPUT
  32. #define INCL_WINDIALOGS
  33. #define INCL_DOSSEMAPHORES
  34. #define INCL_WINFRAMEMGR
  35. #define INCL_WINMENUS
  36.  
  37. #include <os2.h>
  38. #include <string.h>
  39. #include <stdlib.h>
  40. #include <stdio.h>
  41. #include "clnpmain.h"
  42. #include "clnphelp.h"
  43. #include "clnpxtrn.h"
  44. #include "namepipe.h"
  45.  
  46. #define  THRD_EXIT_TIMEOUT  10
  47.  
  48. /*--------------------------------------------------------------*\
  49.  *  Global variables
  50. \*--------------------------------------------------------------*/
  51.  
  52. HWND   hwndMainFrame = NULLHANDLE;    /* handle to the main frame window */
  53. HWND   hwndMain;                      /* handle to the main client window */
  54. HWND   hwndMenu;
  55. HAB    hab;                           /* anchor block for the process */
  56. HMQ    hmq;                           /* handle to the process' message queue */
  57. CHAR   szAppName[MAXNAMEL];           /* buffer for application name string */
  58. BOOL   fHelpEnabled=FALSE;            /* flag to determine if help is enabled */
  59. BOOL   fAppExit=FALSE;                /* flag to signal application exit */
  60. BOOL   fMyTurn=FALSE;                 /* flag allowing client to move */
  61. USHORT usWhosX=CLIENT_NUM;            /* flag denoting who is X piece */
  62. ULONG  ulActiveSquare=0;              /* window id of selected child */
  63. HEV    hevWritePipe;                  /* event semaphore notifying pipe thread of message */
  64. PIPE_MSG  pmsgPipeMsg;                /* message to be written to pipe */
  65. BOOL   fThrdsDead=FALSE;              /* notification of thread exitting */
  66.  
  67.  
  68. /****************************************************************\
  69.  *  Main routine
  70.  *--------------------------------------------------------------
  71.  *
  72.  *  Name:   main()
  73.  *
  74.  *  Purpose: Initializes the PM environment, calls the
  75.  *              initialization routine, creates the main
  76.  *              window,  and polls the message queue
  77.  *
  78.  *  Usage:
  79.  *
  80.  *  Method:
  81.  *          - obtains anchor block handle and creates message
  82.  *              queue
  83.  *          - calls the initialization routine
  84.  *          - creates the main frame window which creates the
  85.  *              main client window
  86.  *          - polls the message queue via Get/Dispatch Msg loop
  87.  *          - upon exiting the loop, exits
  88.  *
  89.  *  Returns:
  90.  *          0 - if successful execution completed
  91.  *          1 - if error
  92. \****************************************************************/
  93. INT main()
  94. {
  95.    QMSG   qmsg;          /* message structure */
  96.    ULONG  ulPosts;
  97.  
  98.    hab = WinInitialize(0);
  99.  
  100.    if(!hab)
  101.    {
  102.       DosBeep(BEEP_WARN_FREQ, BEEP_WARN_DUR);
  103.       return(RETURN_ERROR);
  104.    }
  105.  
  106.    hmq = WinCreateMsgQueue(hab, 0);
  107.  
  108.    if(!hmq)
  109.    {
  110.       DosBeep(BEEP_WARN_FREQ, BEEP_WARN_DUR);
  111.       WinTerminate(hab);
  112.       return(RETURN_ERROR);
  113.    }
  114.  
  115.    if(!Init())
  116.    {
  117.       if(hwndMainFrame == NULLHANDLE)
  118.       {
  119.           MessageBox(HWND_DESKTOP,
  120.                      IDMSG_MAINWINCREATEFAILED,
  121.                      0,
  122.                      MB_OK | MB_ERROR,
  123.                      NULL,
  124.                      TRUE);
  125.       }
  126.  
  127.       else
  128.       {
  129.          MessageBox(HWND_DESKTOP,
  130.                     IDMSG_INITFAILED,
  131.                      0,
  132.                     MB_OK | MB_ERROR,
  133.                     NULL,
  134.                     TRUE);
  135.  
  136.       }
  137.       DosBeep(BEEP_WARN_FREQ, BEEP_WARN_DUR);
  138.       if (WinIsWindow(hab, hwndMainFrame))
  139.       {
  140.          WinDestroyWindow(hwndMainFrame);
  141.       }
  142.       WinDestroyMsgQueue(hmq);
  143.       WinTerminate(hab);
  144.       return(RETURN_ERROR);
  145.    }
  146.  
  147.    /* Get-Dispatch Message loop */
  148.    while(WinGetMsg(hab, (PQMSG)&qmsg, NULLHANDLE, 0, 0))
  149.       WinDispatchMsg(hab, (PQMSG)&qmsg);
  150.  
  151.    /* destroy the help instance */
  152.    DestroyHelpInstance();
  153.  
  154.    if (WinIsWindow(hab, hwndMainFrame))
  155.    {
  156.       WinDestroyWindow(hwndMainFrame);
  157.    }
  158.    WinDestroyMsgQueue(hmq);
  159.  
  160.    WinTerminate(hab);
  161.    return(RETURN_SUCCESS);
  162.  
  163. }   /* main() */
  164.  
  165.  
  166. /****************************************************************\
  167.  *  Main client window procedure
  168.  *--------------------------------------------------------------
  169.  *
  170.  *  Name:   MainWndProc(hwnd, msg, mp1, mp2)
  171.  *
  172.  *  Purpose: Processes the messages sent to the main client
  173.  *              window.  This routine processes the basic
  174.  *              messages all client windows should process
  175.  *              and passes all others onto WinDefWindowProc.
  176.  *
  177.  *  Usage:  Called for each message placed in the main
  178.  *          window's message queue
  179.  *
  180.  *  Method: a switch statement branches to the routines to be
  181.  *          performed for each message processed.
  182.  *
  183.  *  Returns:  Return values are determined by each message
  184.  *
  185. \****************************************************************/
  186. MRESULT EXPENTRY MainWndProc(HWND   hwnd,    /* handle of window */
  187.                              ULONG  msg,     /* id of message */
  188.                              MPARAM mp1,     /* first message parameter */
  189.                              MPARAM mp2)     /* second message parameter */
  190. {
  191.    USHORT       usMsg=IDMSG_CLIENT_WIN;
  192.    LONG         xBlock, yBlock;
  193.    CHAR         *szChildClass = "TicTacToeSquare", *pszWinMsg="YOU WON ! !";
  194.    int          i, j;
  195.    HWND         hwndSquare;
  196.    ULONG        ulOldSquare;
  197.    static HWND  hwndChild[DIVISIONS][DIVISIONS];
  198.    static int   iCloseCount=0;
  199.  
  200.    switch(msg)
  201.    {
  202.       case WM_CREATE:
  203.  
  204.          WinRegisterClass (hab, szChildClass, ChildWndProc,
  205.                            CS_SIZEREDRAW, sizeof(ULONG)*2) ;
  206.  
  207.          for (i = 0 ; i < DIVISIONS ; i++)
  208.          {
  209.             for (j = 0 ; j < DIVISIONS ; j++)
  210.             {
  211.                hwndChild [i][j] = WinCreateWindow (
  212.                                                hwnd,          /* Parent window   */
  213.                                                szChildClass,  /* Window class    */
  214.                                                NULL,          /* Window text     */
  215.                                                WS_VISIBLE |   /* Window style    */
  216.                                                WS_SYNCPAINT,
  217.                                                0, 0, 0, 0,    /* Position & size */
  218.                                                hwnd,          /* Owner window    */
  219.                                                HWND_BOTTOM,   /* Placement       */
  220.                                                (i*DIVISIONS+j), /* Child window ID */
  221.                                        (PVOID) NULL,          /* Control data    */
  222.                                        (PVOID) NULL) ;        /* Pres. Params    */
  223.                /* set window id in window data area */
  224.                if (NULLHANDLE == hwndChild[i][j] ||
  225.                    FALSE == WinSetWindowULong(hwndChild[i][j],
  226.                                               sizeof(ULONG),
  227.                                               (i * DIVISIONS + j)))
  228.                {
  229.                   return (MRFROMLONG(1));
  230.                }
  231.             }
  232.          }
  233.  
  234.          break;
  235.  
  236.       case WM_BUTTON1DOWN:
  237.       case WM_BUTTON1DBLCLK:
  238.            WinAlarm (HWND_DESKTOP, WA_WARNING) ;
  239.            break ;
  240.  
  241.       case WM_SIZE:
  242.          xBlock = SHORT1FROMMP (mp2) / DIVISIONS ;
  243.          yBlock = SHORT2FROMMP (mp2) / DIVISIONS ;
  244.  
  245.          for (i = 0 ; i < DIVISIONS ; i++)
  246.          {
  247.             for (j = 0 ; j < DIVISIONS ; j++)
  248.             {
  249.                if (FALSE == WinSetWindowPos (hwndChild[j][i], NULLHANDLE,
  250.                                              (i * xBlock), (j * yBlock),
  251.                                              xBlock, yBlock,
  252.                                              (SWP_MOVE | SWP_SIZE)))
  253.                {
  254.                   return (MRFROMLONG(1));
  255.                }
  256.             }
  257.          }
  258.          break;
  259.  
  260.       case WM_ERASEBACKGROUND:
  261.            return MRFROMLONG(1);
  262.  
  263.       case WM_CHAR:
  264.          if (SHORT1FROMMP(mp1) & KC_KEYUP)
  265.             break;
  266.  
  267.          if (!(SHORT1FROMMP(mp1) & KC_VIRTUALKEY))
  268.             break;
  269.  
  270.          ulOldSquare = ulActiveSquare;
  271.  
  272.          switch (SHORT2FROMMP(mp2))
  273.          {
  274.             case VK_TAB:
  275.                /* make next client window active window */
  276.                ulActiveSquare = (((DIVISIONS*DIVISIONS-1) == ulActiveSquare) ? 0 : ulActiveSquare+1);
  277.                break;
  278.  
  279.             case VK_BACKTAB:
  280.                /* make previous client window active window */
  281.                ulActiveSquare = ((0 == ulActiveSquare) ? (DIVISIONS*DIVISIONS-1) : ulActiveSquare-1);
  282.                break;
  283.  
  284.             case VK_LEFT:
  285.                /* make client window to left active window */
  286.                ulActiveSquare = ((((ulActiveSquare-1)/DIVISIONS) == (ulActiveSquare/DIVISIONS)) ? ulActiveSquare-1 : ulActiveSquare+(DIVISIONS-1));
  287.                break;
  288.  
  289.             case VK_RIGHT:
  290.                /* make client window to right active window */
  291.                ulActiveSquare = ((((ulActiveSquare+1)/DIVISIONS) == (ulActiveSquare/DIVISIONS)) ? ulActiveSquare+1 : ulActiveSquare+1-DIVISIONS);
  292.                break;
  293.  
  294.             case VK_UP:
  295.                /* make client window above active window */
  296.                ulActiveSquare = ((ulActiveSquare+DIVISIONS < (DIVISIONS*DIVISIONS)) ? ulActiveSquare+DIVISIONS : ulActiveSquare-((DIVISIONS-1)*DIVISIONS));
  297.                break;
  298.  
  299.             case VK_DOWN:
  300.                /* make client window below active window */
  301.                /* ulActiveSquares is unsigned, so instead of testing for */
  302.                /* less than zero, test for greater than it is allowed to be */
  303.                ulActiveSquare = (((ulActiveSquare-DIVISIONS) < (DIVISIONS*DIVISIONS)) ? ulActiveSquare-DIVISIONS : ulActiveSquare+((DIVISIONS-1)*DIVISIONS));
  304.                break;
  305.  
  306.             case VK_NEWLINE:
  307.             case VK_ENTER:
  308.             case VK_SPACE:
  309.                WinPostMsg(WinWindowFromID(hwnd, ulActiveSquare), WM_BUTTON1DOWN, MPVOID, MPVOID);
  310.                break;
  311.          }
  312.  
  313.          /* have squares repaint themselves */
  314.          WinInvalidateRect(WinWindowFromID(hwnd, ulOldSquare), NULL, FALSE);
  315.          WinInvalidateRect(WinWindowFromID(hwnd, ulActiveSquare), NULL, FALSE);
  316.          break ;
  317.  
  318.       case WM_COMMAND:
  319.          MainCommand(mp1, mp2);
  320.          break;
  321.  
  322.       case HM_QUERY_KEYS_HELP:
  323.          return (MRESULT)PANEL_HELPKEYS;   /* return id of key help panel */
  324.          break ;
  325.  
  326.       case WM_START:
  327.          WinEnableMenuItem(hwndMenu, IDM_FILESTART, TRUE);
  328.          break;
  329.  
  330.       case WM_SERVER_MOVE:
  331.          /* set window to server playing piece */
  332.          WinSetWindowULong((hwndSquare=WinWindowFromID(hwnd, SHORT1FROMMP(mp1))),
  333.                            0,
  334.                            SERVER_NUM);
  335.  
  336.          /* repaint square */
  337.          WinInvalidateRect(hwndSquare, NULL, FALSE);
  338.          fMyTurn = TRUE;
  339.          break;
  340.  
  341.       case WM_DRAW:
  342.          usMsg = IDMSG_DRAW;
  343.          pszWinMsg = "Game is a Draw";
  344.          /* NO BREAK */
  345.  
  346.       case WM_WIN_SERVER:
  347.          if (SHORT1FROMMP(mp1) < DIVISIONS*DIVISIONS)
  348.          {
  349.             /* display winning move */
  350.             WinSetWindowULong((hwndSquare=WinWindowFromID(hwnd, SHORT1FROMMP(mp1))),
  351.                               0,
  352.                               SERVER_NUM);
  353.             WinInvalidateRect(hwndSquare, NULL, FALSE);
  354.             if (msg != WM_DRAW)
  355.             {
  356.                usMsg = IDMSG_SERVER_WIN;
  357.                pszWinMsg = "I WON ! !";
  358.             }
  359.          }
  360.          /* NO BREAK */
  361.  
  362.       case WM_WIN_CLIENT:
  363.          if (MBID_YES == MessageBox(hwndMain, usMsg, 0, MB_YESNO | MB_ICONQUESTION, pszWinMsg, TRUE))
  364.          {
  365.             InitBoard();
  366.          }
  367.  
  368.          else
  369.          {
  370.             WinPostMsg(hwndMain, WM_COMMAND, MPFROMLONG(IDM_FILEEXIT), MPVOID);
  371.          }
  372.          break;
  373.  
  374.       case WM_MSG:
  375.          /* default message box */
  376.          if (MPVOID == mp2)
  377.          {
  378.             MessageBox(hwndMain, SHORT1FROMMP(mp1), LONGFROMMP(mp2), MB_OK | MB_ICONEXCLAMATION, NULL, TRUE);
  379.          }
  380.  
  381.          /* custom message box */
  382.          else
  383.          {
  384.             MessageBox(hwndMain, SHORT1FROMMP(mp1), LONGFROMMP(mp2), SHORT2FROMMP(mp1), NULL, TRUE);
  385.          }
  386.          break;
  387.  
  388.       case WM_CLOSE:
  389.          fAppExit = TRUE;
  390.          PostPipeMsg(CLIENT_QUIT, 0);
  391.  
  392.          /* give other thread a chance to exit */
  393.          /* but don't wait around forever for it */
  394.  
  395.          for (iCloseCount = 0; FALSE == fThrdsDead && iCloseCount < THRD_EXIT_TIMEOUT; iCloseCount++)
  396.          {
  397.             DosSleep(0);
  398.          }
  399.  
  400.          /* process the WM_CLOSE */
  401.  
  402.    /*--------------------------------------------------*\
  403.     *      Any messages not processed are passed on
  404.     *      to WinDefWindowProc.
  405.    \*--------------------------------------------------*/
  406.  
  407.       default:
  408.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  409.          break;
  410.    }
  411.  
  412.    return (MRFROMLONG(0));      /* all window procedures should return 0 as a default */
  413.  
  414. }   /* MainWndProc() */
  415.  
  416.  
  417. /****************************************************************\
  418.  *  Message Box procedure
  419.  *--------------------------------------------------------------
  420.  *
  421.  *  Name:   MessageBox(hwndOwner, nIdMsg, lRC, fsStyle, pszTitle, fBeep)
  422.  *
  423.  *  Purpose: Displays the message box with the message
  424.  *              given in idMsg retrieved from the message table
  425.  *              and using the style flags in fsStyle
  426.  *
  427.  *  Usage:  Called whenever a MessageBox is to be displayed
  428.  *
  429.  *  Method: - Message string is loaded from the process'
  430.  *              message table
  431.  *          - Alarm beep is sounded if desired
  432.  *          - Message box with the message is displayed
  433.  *          - WinMessageBox return value is returned
  434.  *
  435.  *  Returns: return value from WinMessageBox()
  436.  *
  437. \****************************************************************/
  438.  
  439. ULONG MessageBox(HWND  hwndOwner, /* handle of the message box's owner */
  440.                  ULONG idMsg,     /* id if the message in the message table */
  441.                  LONG  lRC,       /* return code of failing function */
  442.                  ULONG fsStyle,   /* style of the message box */
  443.                  PSZ   pszTitle,  /* title of message box */
  444.                  BOOL  fBeep)     /* if TRUE, beep before message box is displayed */
  445. {
  446.    CHAR szText[TITLE_LEN];
  447.  
  448.    if(!WinLoadMessage(hab,
  449.                      (HMODULE)NULL,
  450.                      idMsg,
  451.                      TITLE_LEN,
  452.                      (PSZ)szText))
  453.    {
  454.       WinAlarm(HWND_DESKTOP, WA_ERROR);
  455.       return MBID_ERROR;
  456.    }
  457.  
  458.    if (NULL == pszTitle)
  459.    {
  460.       pszTitle = "Client Error";
  461.    }
  462.  
  463.    if (lRC)
  464.    {
  465.       sprintf(szText, "%s\n rc = %lu", szText, lRC);
  466.    }
  467.  
  468.    if(fBeep)  {
  469.       WinAlarm(HWND_DESKTOP, WA_ERROR);
  470.    }
  471.  
  472.    return(WinMessageBox(HWND_DESKTOP,
  473.                         hwndOwner,
  474.                         szText,
  475.                         pszTitle,
  476.                         MSGBOXID,
  477.                         fsStyle));
  478.  
  479. }   /* MessageBox() */
  480.  
  481.  
  482. /****************************************************************\
  483.  *  Main window WM_COMMAND processing procedure
  484.  *--------------------------------------------------------------
  485.  *
  486.  *  Name:   MainCommand(mp1, mp2)
  487.  *
  488.  *  Purpose: Calls the appropriate procedures that deal with
  489.  *              the selected menu item.
  490.  *
  491.  *  Usage:  Routine is called whenever a WM_COMMAND message
  492.  *          is posted to the main window.
  493.  *
  494.  *  Method: a switch statement branches on the id of the
  495.  *          menu item that posted the message and the
  496.  *          appropriate action for that item is taken.
  497.  *
  498.  *  Returns:
  499.  *
  500. \****************************************************************/
  501. VOID MainCommand(MPARAM mp1, MPARAM mp2)
  502. {
  503.  
  504.    switch(SHORT1FROMMP(mp1))
  505.    {
  506.       case IDM_FILEEXIT:
  507.          FileExit();
  508.          break;
  509.  
  510.       case IDM_FILESTART:
  511.          /* ask player who should move first, perhaps with a message box */
  512.          WinEnableMenuItem(hwndMenu, IDM_FILESTART, FALSE);
  513.          if (MBID_YES == MessageBox(hwndMain, IDMSG_ME_FIRST, 0, MB_ICONQUESTION | MB_YESNO, "", FALSE))
  514.          {
  515.             fMyTurn = TRUE;
  516.          }
  517.  
  518.          else
  519.          {
  520.             PostPipeMsg(YOU_FIRST, 0);
  521.          }
  522.          break;
  523.  
  524.       case IDM_OPTIONSWAPPIECES:
  525.          usWhosX = (USHORT)((SERVER_NUM == usWhosX) ? CLIENT_NUM : SERVER_NUM);
  526.          WinInvalidateRect(hwndMain, NULL, TRUE);
  527.          break;
  528.  
  529.       case IDM_HELPHELPFORHELP:
  530.          HelpHelpForHelp(mp2);
  531.          break;
  532.  
  533.       case IDM_HELPEXTENDED:
  534.          HelpExtended(mp2);
  535.          break;
  536.  
  537.       case IDM_HELPKEYS:
  538.          HelpKeys(mp2);
  539.          break;
  540.  
  541.       case IDM_HELPINDEX:
  542.          HelpIndex(mp2);
  543.          break;
  544.  
  545.       case IDM_HELPTUTORIAL:
  546.          HelpTutorial(mp2);
  547.          break;
  548.  
  549.       case IDM_HELPABOUT:
  550.          HelpAbout(mp2);
  551.          break;
  552.  
  553.       default:
  554.          break;
  555.     }
  556.  
  557. }   /* MainCommand() */
  558.  
  559.  
  560. /*
  561.  *   Window procedure for each tic-tac-toe square.
  562.  */
  563. MRESULT EXPENTRY ChildWndProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  564. {
  565.    HPS     hps ;
  566.    RECTL   rcl ;
  567.    USHORT  usWinState;
  568.    ULONG   ulOldSquare;
  569.  
  570.    switch (msg)
  571.    {
  572.       case WM_CREATE:
  573.          /* initialize square as empty */
  574.          WinSetWindowULong (hwnd, 0, 0) ;
  575.          break;
  576.  
  577.       case WM_BUTTON1DOWN:
  578.          if (fMyTurn && 0 == (BOOL)WinQueryWindowULong (hwnd, 0))
  579.          {
  580.             fMyTurn = FALSE;
  581.             PostPipeMsg(CLIENT_MOVE, WinQueryWindowULong(hwnd, sizeof(ULONG)));
  582.             ulOldSquare = ulActiveSquare;
  583.             ulActiveSquare = WinQueryWindowULong(hwnd, sizeof(ULONG));
  584.             WinSetWindowULong (hwnd, 0, CLIENT_NUM);
  585.             WinInvalidateRect(WinWindowFromID(hwndMain, ulOldSquare), NULL, FALSE);
  586.             WinInvalidateRect(hwnd, NULL, FALSE);
  587.             WinSetActiveWindow (HWND_DESKTOP, hwnd);
  588.          }
  589.  
  590.          else
  591.          {
  592.             WinAlarm(HWND_DESKTOP, WA_ERROR);
  593.          }
  594.          break;
  595.  
  596.       case WM_PAINT:
  597.          WinQueryWindowRect (hwnd, &rcl) ;
  598.  
  599.          hps = WinBeginPaint (hwnd, NULLHANDLE, NULL) ;
  600.  
  601.          if (WinQueryWindowULong(hwnd, sizeof(ULONG)) == ulActiveSquare)
  602.          {
  603.             WinDrawBorder (hps, &rcl, 2, 2, CLR_NEUTRAL, CLR_BACKGROUND,
  604.                            DB_STANDARD | DB_INTERIOR) ;
  605.          }
  606.  
  607.          else
  608.          {
  609.             WinDrawBorder (hps, &rcl, 1, 1, CLR_NEUTRAL, CLR_BACKGROUND,
  610.                            DB_STANDARD | DB_INTERIOR) ;
  611.          }
  612.  
  613.          if ((BOOL)(usWinState = (USHORT)WinQueryWindowULong (hwnd, 0)))
  614.          {
  615.             DrawPiece(hps, usWinState, rcl);
  616.          }
  617.  
  618.          WinEndPaint (hps) ;
  619.          break;
  620.  
  621.       case WM_CHAR:
  622.          switch (SHORT2FROMMP(mp2))
  623.          {
  624.             case VK_NEWLINE:
  625.             case VK_ENTER:
  626.             case VK_SPACE:
  627.                if (fMyTurn && 0 == (BOOL)WinQueryWindowULong (hwnd, 0))
  628.                {
  629.                   fMyTurn = FALSE;
  630.                   PostPipeMsg(CLIENT_MOVE, WinQueryWindowULong(hwnd, sizeof(ULONG)));
  631.                   WinSetWindowULong (hwnd, 0, CLIENT_NUM);
  632.                   WinInvalidateRect (hwnd, NULL, FALSE);
  633.                }
  634.  
  635.                else
  636.                {
  637.                   WinAlarm(HWND_DESKTOP, WA_ERROR);
  638.                }
  639.  
  640.                break;
  641.  
  642.             default:
  643.                /* let the main window deal with it */
  644.                WinPostMsg(hwndMain, msg, mp1, mp2);
  645.          }
  646.          break;
  647.  
  648.       default:
  649.          return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  650.    }
  651.    return MRFROMLONG(0);
  652. }
  653.  
  654.  
  655. /****************************************************************\
  656.  *  Initialization routine
  657.  *--------------------------------------------------------------
  658.  *
  659.  *  Name:   Init()
  660.  *
  661.  *  Purpose: Performs initialization functions.
  662.  *
  663.  *  Usage:  Called once before the message queue is queried.
  664.  *
  665.  *  Method:
  666.  *          - starts processing thread
  667.  *          - registers all window classes
  668.  *
  669.  *  Returns:
  670.  *          TRUE - initialization is successful
  671.  *          FALSE - initialization failed
  672. \****************************************************************/
  673. BOOL Init()
  674. {
  675.    ULONG  flCtlData;    /* frame control data */
  676.  
  677.  
  678.    /* load application name from resource file */
  679.    if(!WinLoadString(hab, 0, IDS_APPNAME, MAXNAMEL, szAppName))
  680.    {
  681.       return FALSE;
  682.    }
  683.  
  684.    /* register the main client window class */
  685.    if(!WinRegisterClass(hab,
  686.                         szAppName,
  687.                         MainWndProc,
  688.                         CS_SIZEREDRAW | CS_CLIPCHILDREN,
  689.                         0))
  690.    {
  691.       return FALSE;
  692.    }
  693.  
  694.    flCtlData = FCF_STANDARD;
  695.  
  696.    if (NULLHANDLE ==
  697.        (hwndMainFrame = WinCreateStdWindow(HWND_DESKTOP,
  698.                                            WS_VISIBLE,
  699.                                            &flCtlData,
  700.                                            szAppName,
  701.                                            NULL,
  702.                                            WS_VISIBLE,
  703.                                            NULLHANDLE,
  704.                                            IDR_MAIN,
  705.                                            &hwndMain)))
  706.    {
  707.       return FALSE;
  708.    }
  709.  
  710.    WinSetWindowText(hwndMainFrame, szAppName);
  711.  
  712.    InitHelp();
  713.  
  714.    if (!InitThread())
  715.    {
  716.       return FALSE;
  717.    }
  718.  
  719.    hwndMenu = WinWindowFromID(hwndMainFrame, FID_MENU);
  720.  
  721.    return TRUE;
  722. }  /* Init() */
  723.  
  724.  
  725. /****************************************************************\
  726.  *  Exit routine
  727.  *--------------------------------------------------------------
  728.  *
  729.  *  Name:   FileExit(mp2)
  730.  *
  731.  *  Purpose: Processes the File menu's Exit item.
  732.  *
  733.  *  Usage:  called whenever Exit from the file menu is
  734.  *          selected
  735.  *
  736.  *  Method:  Routine posts a WM_CLOSE message to the main
  737.  *           application window.
  738.  *
  739.  *  Returns:
  740.  *
  741. \****************************************************************/
  742. VOID FileExit()
  743. {
  744.  
  745.    fAppExit = TRUE;
  746.    WinPostMsg(hwndMain, WM_CLOSE, (MPARAM)NULL, (MPARAM)NULL);
  747. }   /* FileExit() */
  748.  
  749.  
  750. /*
  751.  *   Draw X or O in square.
  752.  */
  753. VOID DrawPiece(HPS hps, USHORT usPiece, RECTL rcl)
  754. {
  755.    POINTL ptl;
  756.    LONG   xAxis, yAxis;
  757.  
  758.    if (usWhosX == usPiece)
  759.    {
  760.       /* Draw X */
  761.       ptl.x = rcl.xLeft;
  762.       ptl.y = rcl.yBottom;
  763.       GpiMove (hps, &ptl);
  764.       ptl.x = rcl.xRight;
  765.       ptl.y = rcl.yTop;
  766.       GpiLine (hps, &ptl);
  767.  
  768.       ptl.x = rcl.xLeft;
  769.       ptl.y = rcl.yTop;
  770.       GpiMove (hps, &ptl);
  771.       ptl.x = rcl.xRight;
  772.       ptl.y = rcl.yBottom;
  773.       GpiLine (hps, &ptl);
  774.    }
  775.  
  776.    else
  777.    {
  778.       /* Draw O */
  779.       ptl.x = rcl.xLeft;
  780.       ptl.y = rcl.yBottom;
  781.       GpiMove (hps, &ptl);
  782.       xAxis = rcl.xRight - rcl.xLeft;
  783.       yAxis = rcl.yTop - rcl.yBottom;
  784.       ptl.x = rcl.xRight;
  785.       ptl.y = rcl.yTop;
  786.       GpiBox(hps, DRO_OUTLINE, &ptl, xAxis, yAxis);
  787.    }
  788. }
  789.  
  790.  
  791. /*
  792.  *   Copy message to buffer and post event semaphore.
  793.  */
  794. VOID PostPipeMsg(USHORT usMsg, USHORT usData)
  795. {
  796.  
  797.    pmsgPipeMsg.usMsgType = usMsg;
  798.    pmsgPipeMsg.usMsgData = usData;
  799.    DosPostEventSem(hevWritePipe);
  800. }
  801.  
  802.  
  803. /*
  804.  *   Erase game board.
  805.  */
  806. VOID InitBoard()
  807. {
  808.    int i, j;
  809.  
  810.    fMyTurn = FALSE;
  811.    for (i = 0 ; i < DIVISIONS ; i++)
  812.    {
  813.       for (j = 0 ; j < DIVISIONS ; j++)
  814.       {
  815.          WinSetWindowULong(WinWindowFromID(hwndMain, (DIVISIONS*i+j)), 0, 0);
  816.       }
  817.    }
  818.  
  819.    WinInvalidateRect(hwndMain, NULL, TRUE);
  820.    WinEnableMenuItem(hwndMenu, IDM_FILESTART, TRUE);
  821. }
  822.