home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
VSCPPv8.zip
/
VACPP
/
IBMCPP
/
samples
/
TOOLKIT
/
OS2
/
NPIPE
/
CLNPMAIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-11-17
|
25KB
|
822 lines
/*==============================================================*\
* clnpmain.c - Pipe Server end of Tic-Tac-Toe sample app
* Copyright 1992 IBM Corp.
*--------------------------------------------------------------
*
* DISCLAIMER OF WARRANTIES. The following [enclosed] code is
* sample code created by IBM Corporation. This sample code is not
* part of any standard or IBM product and is provided to you solely
* for the purpose of assisting you in the development of your
* applications. The code is provided "AS IS", without
* warranty of any kind. IBM shall not be liable for any damages
* arising out of your use of the sample code, even if they have been
* advised of the possibility of such damages. *
*
*--------------------------------------------------------------
*
* This c file contains the window creation routines and
* manages the PM message queue.
*
\*==============================================================*/
/*--------------------------------------------------------------*\
* Include files, macros, defined constants, and externs
\*--------------------------------------------------------------*/
#define INCL_WINHELP
#define INCL_DOSPROCESS
#define INCL_WINMESSAGEMGR
#define INCL_WINWINDOWMGR
#define INCL_WININPUT
#define INCL_WINDIALOGS
#define INCL_DOSSEMAPHORES
#define INCL_WINFRAMEMGR
#define INCL_WINMENUS
#include <os2.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "clnpmain.h"
#include "clnphelp.h"
#include "clnpxtrn.h"
#include "namepipe.h"
#define THRD_EXIT_TIMEOUT 10
/*--------------------------------------------------------------*\
* Global variables
\*--------------------------------------------------------------*/
HWND hwndMainFrame = NULLHANDLE; /* handle to the main frame window */
HWND hwndMain; /* handle to the main client window */
HWND hwndMenu;
HAB hab; /* anchor block for the process */
HMQ hmq; /* handle to the process' message queue */
CHAR szAppName[MAXNAMEL]; /* buffer for application name string */
BOOL fHelpEnabled=FALSE; /* flag to determine if help is enabled */
BOOL fAppExit=FALSE; /* flag to signal application exit */
BOOL fMyTurn=FALSE; /* flag allowing client to move */
USHORT usWhosX=CLIENT_NUM; /* flag denoting who is X piece */
ULONG ulActiveSquare=0; /* window id of selected child */
HEV hevWritePipe; /* event semaphore notifying pipe thread of message */
PIPE_MSG pmsgPipeMsg; /* message to be written to pipe */
BOOL fThrdsDead=FALSE; /* notification of thread exitting */
/****************************************************************\
* Main routine
*--------------------------------------------------------------
*
* Name: main()
*
* Purpose: Initializes the PM environment, calls the
* initialization routine, creates the main
* window, and polls the message queue
*
* Usage:
*
* Method:
* - obtains anchor block handle and creates message
* queue
* - calls the initialization routine
* - creates the main frame window which creates the
* main client window
* - polls the message queue via Get/Dispatch Msg loop
* - upon exiting the loop, exits
*
* Returns:
* 0 - if successful execution completed
* 1 - if error
\****************************************************************/
INT main()
{
QMSG qmsg; /* message structure */
ULONG ulPosts;
hab = WinInitialize(0);
if(!hab)
{
DosBeep(BEEP_WARN_FREQ, BEEP_WARN_DUR);
return(RETURN_ERROR);
}
hmq = WinCreateMsgQueue(hab, 0);
if(!hmq)
{
DosBeep(BEEP_WARN_FREQ, BEEP_WARN_DUR);
WinTerminate(hab);
return(RETURN_ERROR);
}
if(!Init())
{
if(hwndMainFrame == NULLHANDLE)
{
MessageBox(HWND_DESKTOP,
IDMSG_MAINWINCREATEFAILED,
0,
MB_OK | MB_ERROR,
NULL,
TRUE);
}
else
{
MessageBox(HWND_DESKTOP,
IDMSG_INITFAILED,
0,
MB_OK | MB_ERROR,
NULL,
TRUE);
}
DosBeep(BEEP_WARN_FREQ, BEEP_WARN_DUR);
if (WinIsWindow(hab, hwndMainFrame))
{
WinDestroyWindow(hwndMainFrame);
}
WinDestroyMsgQueue(hmq);
WinTerminate(hab);
return(RETURN_ERROR);
}
/* Get-Dispatch Message loop */
while(WinGetMsg(hab, (PQMSG)&qmsg, NULLHANDLE, 0, 0))
WinDispatchMsg(hab, (PQMSG)&qmsg);
/* destroy the help instance */
DestroyHelpInstance();
if (WinIsWindow(hab, hwndMainFrame))
{
WinDestroyWindow(hwndMainFrame);
}
WinDestroyMsgQueue(hmq);
WinTerminate(hab);
return(RETURN_SUCCESS);
} /* main() */
/****************************************************************\
* Main client window procedure
*--------------------------------------------------------------
*
* Name: MainWndProc(hwnd, msg, mp1, mp2)
*
* Purpose: Processes the messages sent to the main client
* window. This routine processes the basic
* messages all client windows should process
* and passes all others onto WinDefWindowProc.
*
* Usage: Called for each message placed in the main
* window's message queue
*
* Method: a switch statement branches to the routines to be
* performed for each message processed.
*
* Returns: Return values are determined by each message
*
\****************************************************************/
MRESULT EXPENTRY MainWndProc(HWND hwnd, /* handle of window */
ULONG msg, /* id of message */
MPARAM mp1, /* first message parameter */
MPARAM mp2) /* second message parameter */
{
USHORT usMsg=IDMSG_CLIENT_WIN;
LONG xBlock, yBlock;
CHAR *szChildClass = "TicTacToeSquare", *pszWinMsg="YOU WON ! !";
int i, j;
HWND hwndSquare;
ULONG ulOldSquare;
static HWND hwndChild[DIVISIONS][DIVISIONS];
static int iCloseCount=0;
switch(msg)
{
case WM_CREATE:
WinRegisterClass (hab, szChildClass, ChildWndProc,
CS_SIZEREDRAW, sizeof(ULONG)*2) ;
for (i = 0 ; i < DIVISIONS ; i++)
{
for (j = 0 ; j < DIVISIONS ; j++)
{
hwndChild [i][j] = WinCreateWindow (
hwnd, /* Parent window */
szChildClass, /* Window class */
NULL, /* Window text */
WS_VISIBLE | /* Window style */
WS_SYNCPAINT,
0, 0, 0, 0, /* Position & size */
hwnd, /* Owner window */
HWND_BOTTOM, /* Placement */
(i*DIVISIONS+j), /* Child window ID */
(PVOID) NULL, /* Control data */
(PVOID) NULL) ; /* Pres. Params */
/* set window id in window data area */
if (NULLHANDLE == hwndChild[i][j] ||
FALSE == WinSetWindowULong(hwndChild[i][j],
sizeof(ULONG),
(i * DIVISIONS + j)))
{
return (MRFROMLONG(1));
}
}
}
break;
case WM_BUTTON1DOWN:
case WM_BUTTON1DBLCLK:
WinAlarm (HWND_DESKTOP, WA_WARNING) ;
break ;
case WM_SIZE:
xBlock = SHORT1FROMMP (mp2) / DIVISIONS ;
yBlock = SHORT2FROMMP (mp2) / DIVISIONS ;
for (i = 0 ; i < DIVISIONS ; i++)
{
for (j = 0 ; j < DIVISIONS ; j++)
{
if (FALSE == WinSetWindowPos (hwndChild[j][i], NULLHANDLE,
(i * xBlock), (j * yBlock),
xBlock, yBlock,
(SWP_MOVE | SWP_SIZE)))
{
return (MRFROMLONG(1));
}
}
}
break;
case WM_ERASEBACKGROUND:
return MRFROMLONG(1);
case WM_CHAR:
if (SHORT1FROMMP(mp1) & KC_KEYUP)
break;
if (!(SHORT1FROMMP(mp1) & KC_VIRTUALKEY))
break;
ulOldSquare = ulActiveSquare;
switch (SHORT2FROMMP(mp2))
{
case VK_TAB:
/* make next client window active window */
ulActiveSquare = (((DIVISIONS*DIVISIONS-1) == ulActiveSquare) ? 0 : ulActiveSquare+1);
break;
case VK_BACKTAB:
/* make previous client window active window */
ulActiveSquare = ((0 == ulActiveSquare) ? (DIVISIONS*DIVISIONS-1) : ulActiveSquare-1);
break;
case VK_LEFT:
/* make client window to left active window */
ulActiveSquare = ((((ulActiveSquare-1)/DIVISIONS) == (ulActiveSquare/DIVISIONS)) ? ulActiveSquare-1 : ulActiveSquare+(DIVISIONS-1));
break;
case VK_RIGHT:
/* make client window to right active window */
ulActiveSquare = ((((ulActiveSquare+1)/DIVISIONS) == (ulActiveSquare/DIVISIONS)) ? ulActiveSquare+1 : ulActiveSquare+1-DIVISIONS);
break;
case VK_UP:
/* make client window above active window */
ulActiveSquare = ((ulActiveSquare+DIVISIONS < (DIVISIONS*DIVISIONS)) ? ulActiveSquare+DIVISIONS : ulActiveSquare-((DIVISIONS-1)*DIVISIONS));
break;
case VK_DOWN:
/* make client window below active window */
/* ulActiveSquares is unsigned, so instead of testing for */
/* less than zero, test for greater than it is allowed to be */
ulActiveSquare = (((ulActiveSquare-DIVISIONS) < (DIVISIONS*DIVISIONS)) ? ulActiveSquare-DIVISIONS : ulActiveSquare+((DIVISIONS-1)*DIVISIONS));
break;
case VK_NEWLINE:
case VK_ENTER:
case VK_SPACE:
WinPostMsg(WinWindowFromID(hwnd, ulActiveSquare), WM_BUTTON1DOWN, MPVOID, MPVOID);
break;
}
/* have squares repaint themselves */
WinInvalidateRect(WinWindowFromID(hwnd, ulOldSquare), NULL, FALSE);
WinInvalidateRect(WinWindowFromID(hwnd, ulActiveSquare), NULL, FALSE);
break ;
case WM_COMMAND:
MainCommand(mp1, mp2);
break;
case HM_QUERY_KEYS_HELP:
return (MRESULT)PANEL_HELPKEYS; /* return id of key help panel */
break ;
case WM_START:
WinEnableMenuItem(hwndMenu, IDM_FILESTART, TRUE);
break;
case WM_SERVER_MOVE:
/* set window to server playing piece */
WinSetWindowULong((hwndSquare=WinWindowFromID(hwnd, SHORT1FROMMP(mp1))),
0,
SERVER_NUM);
/* repaint square */
WinInvalidateRect(hwndSquare, NULL, FALSE);
fMyTurn = TRUE;
break;
case WM_DRAW:
usMsg = IDMSG_DRAW;
pszWinMsg = "Game is a Draw";
/* NO BREAK */
case WM_WIN_SERVER:
if (SHORT1FROMMP(mp1) < DIVISIONS*DIVISIONS)
{
/* display winning move */
WinSetWindowULong((hwndSquare=WinWindowFromID(hwnd, SHORT1FROMMP(mp1))),
0,
SERVER_NUM);
WinInvalidateRect(hwndSquare, NULL, FALSE);
if (msg != WM_DRAW)
{
usMsg = IDMSG_SERVER_WIN;
pszWinMsg = "I WON ! !";
}
}
/* NO BREAK */
case WM_WIN_CLIENT:
if (MBID_YES == MessageBox(hwndMain, usMsg, 0, MB_YESNO | MB_ICONQUESTION, pszWinMsg, TRUE))
{
InitBoard();
}
else
{
WinPostMsg(hwndMain, WM_COMMAND, MPFROMLONG(IDM_FILEEXIT), MPVOID);
}
break;
case WM_MSG:
/* default message box */
if (MPVOID == mp2)
{
MessageBox(hwndMain, SHORT1FROMMP(mp1), LONGFROMMP(mp2), MB_OK | MB_ICONEXCLAMATION, NULL, TRUE);
}
/* custom message box */
else
{
MessageBox(hwndMain, SHORT1FROMMP(mp1), LONGFROMMP(mp2), SHORT2FROMMP(mp1), NULL, TRUE);
}
break;
case WM_CLOSE:
fAppExit = TRUE;
PostPipeMsg(CLIENT_QUIT, 0);
/* give other thread a chance to exit */
/* but don't wait around forever for it */
for (iCloseCount = 0; FALSE == fThrdsDead && iCloseCount < THRD_EXIT_TIMEOUT; iCloseCount++)
{
DosSleep(0);
}
/* process the WM_CLOSE */
/*--------------------------------------------------*\
* Any messages not processed are passed on
* to WinDefWindowProc.
\*--------------------------------------------------*/
default:
return(WinDefWindowProc(hwnd, msg, mp1, mp2));
break;
}
return (MRFROMLONG(0)); /* all window procedures should return 0 as a default */
} /* MainWndProc() */
/****************************************************************\
* Message Box procedure
*--------------------------------------------------------------
*
* Name: MessageBox(hwndOwner, nIdMsg, lRC, fsStyle, pszTitle, fBeep)
*
* Purpose: Displays the message box with the message
* given in idMsg retrieved from the message table
* and using the style flags in fsStyle
*
* Usage: Called whenever a MessageBox is to be displayed
*
* Method: - Message string is loaded from the process'
* message table
* - Alarm beep is sounded if desired
* - Message box with the message is displayed
* - WinMessageBox return value is returned
*
* Returns: return value from WinMessageBox()
*
\****************************************************************/
ULONG MessageBox(HWND hwndOwner, /* handle of the message box's owner */
ULONG idMsg, /* id if the message in the message table */
LONG lRC, /* return code of failing function */
ULONG fsStyle, /* style of the message box */
PSZ pszTitle, /* title of message box */
BOOL fBeep) /* if TRUE, beep before message box is displayed */
{
CHAR szText[TITLE_LEN];
if(!WinLoadMessage(hab,
(HMODULE)NULL,
idMsg,
TITLE_LEN,
(PSZ)szText))
{
WinAlarm(HWND_DESKTOP, WA_ERROR);
return MBID_ERROR;
}
if (NULL == pszTitle)
{
pszTitle = "Client Error";
}
if (lRC)
{
sprintf(szText, "%s\n rc = %lu", szText, lRC);
}
if(fBeep) {
WinAlarm(HWND_DESKTOP, WA_ERROR);
}
return(WinMessageBox(HWND_DESKTOP,
hwndOwner,
szText,
pszTitle,
MSGBOXID,
fsStyle));
} /* MessageBox() */
/****************************************************************\
* Main window WM_COMMAND processing procedure
*--------------------------------------------------------------
*
* Name: MainCommand(mp1, mp2)
*
* Purpose: Calls the appropriate procedures that deal with
* the selected menu item.
*
* Usage: Routine is called whenever a WM_COMMAND message
* is posted to the main window.
*
* Method: a switch statement branches on the id of the
* menu item that posted the message and the
* appropriate action for that item is taken.
*
* Returns:
*
\****************************************************************/
VOID MainCommand(MPARAM mp1, MPARAM mp2)
{
switch(SHORT1FROMMP(mp1))
{
case IDM_FILEEXIT:
FileExit();
break;
case IDM_FILESTART:
/* ask player who should move first, perhaps with a message box */
WinEnableMenuItem(hwndMenu, IDM_FILESTART, FALSE);
if (MBID_YES == MessageBox(hwndMain, IDMSG_ME_FIRST, 0, MB_ICONQUESTION | MB_YESNO, "", FALSE))
{
fMyTurn = TRUE;
}
else
{
PostPipeMsg(YOU_FIRST, 0);
}
break;
case IDM_OPTIONSWAPPIECES:
usWhosX = (USHORT)((SERVER_NUM == usWhosX) ? CLIENT_NUM : SERVER_NUM);
WinInvalidateRect(hwndMain, NULL, TRUE);
break;
case IDM_HELPHELPFORHELP:
HelpHelpForHelp(mp2);
break;
case IDM_HELPEXTENDED:
HelpExtended(mp2);
break;
case IDM_HELPKEYS:
HelpKeys(mp2);
break;
case IDM_HELPINDEX:
HelpIndex(mp2);
break;
case IDM_HELPTUTORIAL:
HelpTutorial(mp2);
break;
case IDM_HELPABOUT:
HelpAbout(mp2);
break;
default:
break;
}
} /* MainCommand() */
/*
* Window procedure for each tic-tac-toe square.
*/
MRESULT EXPENTRY ChildWndProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
HPS hps ;
RECTL rcl ;
USHORT usWinState;
ULONG ulOldSquare;
switch (msg)
{
case WM_CREATE:
/* initialize square as empty */
WinSetWindowULong (hwnd, 0, 0) ;
break;
case WM_BUTTON1DOWN:
if (fMyTurn && 0 == (BOOL)WinQueryWindowULong (hwnd, 0))
{
fMyTurn = FALSE;
PostPipeMsg(CLIENT_MOVE, WinQueryWindowULong(hwnd, sizeof(ULONG)));
ulOldSquare = ulActiveSquare;
ulActiveSquare = WinQueryWindowULong(hwnd, sizeof(ULONG));
WinSetWindowULong (hwnd, 0, CLIENT_NUM);
WinInvalidateRect(WinWindowFromID(hwndMain, ulOldSquare), NULL, FALSE);
WinInvalidateRect(hwnd, NULL, FALSE);
WinSetActiveWindow (HWND_DESKTOP, hwnd);
}
else
{
WinAlarm(HWND_DESKTOP, WA_ERROR);
}
break;
case WM_PAINT:
WinQueryWindowRect (hwnd, &rcl) ;
hps = WinBeginPaint (hwnd, NULLHANDLE, NULL) ;
if (WinQueryWindowULong(hwnd, sizeof(ULONG)) == ulActiveSquare)
{
WinDrawBorder (hps, &rcl, 2, 2, CLR_NEUTRAL, CLR_BACKGROUND,
DB_STANDARD | DB_INTERIOR) ;
}
else
{
WinDrawBorder (hps, &rcl, 1, 1, CLR_NEUTRAL, CLR_BACKGROUND,
DB_STANDARD | DB_INTERIOR) ;
}
if ((BOOL)(usWinState = (USHORT)WinQueryWindowULong (hwnd, 0)))
{
DrawPiece(hps, usWinState, rcl);
}
WinEndPaint (hps) ;
break;
case WM_CHAR:
switch (SHORT2FROMMP(mp2))
{
case VK_NEWLINE:
case VK_ENTER:
case VK_SPACE:
if (fMyTurn && 0 == (BOOL)WinQueryWindowULong (hwnd, 0))
{
fMyTurn = FALSE;
PostPipeMsg(CLIENT_MOVE, WinQueryWindowULong(hwnd, sizeof(ULONG)));
WinSetWindowULong (hwnd, 0, CLIENT_NUM);
WinInvalidateRect (hwnd, NULL, FALSE);
}
else
{
WinAlarm(HWND_DESKTOP, WA_ERROR);
}
break;
default:
/* let the main window deal with it */
WinPostMsg(hwndMain, msg, mp1, mp2);
}
break;
default:
return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
}
return MRFROMLONG(0);
}
/****************************************************************\
* Initialization routine
*--------------------------------------------------------------
*
* Name: Init()
*
* Purpose: Performs initialization functions.
*
* Usage: Called once before the message queue is queried.
*
* Method:
* - starts processing thread
* - registers all window classes
*
* Returns:
* TRUE - initialization is successful
* FALSE - initialization failed
\****************************************************************/
BOOL Init()
{
ULONG flCtlData; /* frame control data */
/* load application name from resource file */
if(!WinLoadString(hab, 0, IDS_APPNAME, MAXNAMEL, szAppName))
{
return FALSE;
}
/* register the main client window class */
if(!WinRegisterClass(hab,
szAppName,
MainWndProc,
CS_SIZEREDRAW | CS_CLIPCHILDREN,
0))
{
return FALSE;
}
flCtlData = FCF_STANDARD;
if (NULLHANDLE ==
(hwndMainFrame = WinCreateStdWindow(HWND_DESKTOP,
WS_VISIBLE,
&flCtlData,
szAppName,
NULL,
WS_VISIBLE,
NULLHANDLE,
IDR_MAIN,
&hwndMain)))
{
return FALSE;
}
WinSetWindowText(hwndMainFrame, szAppName);
InitHelp();
if (!InitThread())
{
return FALSE;
}
hwndMenu = WinWindowFromID(hwndMainFrame, FID_MENU);
return TRUE;
} /* Init() */
/****************************************************************\
* Exit routine
*--------------------------------------------------------------
*
* Name: FileExit(mp2)
*
* Purpose: Processes the File menu's Exit item.
*
* Usage: called whenever Exit from the file menu is
* selected
*
* Method: Routine posts a WM_CLOSE message to the main
* application window.
*
* Returns:
*
\****************************************************************/
VOID FileExit()
{
fAppExit = TRUE;
WinPostMsg(hwndMain, WM_CLOSE, (MPARAM)NULL, (MPARAM)NULL);
} /* FileExit() */
/*
* Draw X or O in square.
*/
VOID DrawPiece(HPS hps, USHORT usPiece, RECTL rcl)
{
POINTL ptl;
LONG xAxis, yAxis;
if (usWhosX == usPiece)
{
/* Draw X */
ptl.x = rcl.xLeft;
ptl.y = rcl.yBottom;
GpiMove (hps, &ptl);
ptl.x = rcl.xRight;
ptl.y = rcl.yTop;
GpiLine (hps, &ptl);
ptl.x = rcl.xLeft;
ptl.y = rcl.yTop;
GpiMove (hps, &ptl);
ptl.x = rcl.xRight;
ptl.y = rcl.yBottom;
GpiLine (hps, &ptl);
}
else
{
/* Draw O */
ptl.x = rcl.xLeft;
ptl.y = rcl.yBottom;
GpiMove (hps, &ptl);
xAxis = rcl.xRight - rcl.xLeft;
yAxis = rcl.yTop - rcl.yBottom;
ptl.x = rcl.xRight;
ptl.y = rcl.yTop;
GpiBox(hps, DRO_OUTLINE, &ptl, xAxis, yAxis);
}
}
/*
* Copy message to buffer and post event semaphore.
*/
VOID PostPipeMsg(USHORT usMsg, USHORT usData)
{
pmsgPipeMsg.usMsgType = usMsg;
pmsgPipeMsg.usMsgData = usData;
DosPostEventSem(hevWritePipe);
}
/*
* Erase game board.
*/
VOID InitBoard()
{
int i, j;
fMyTurn = FALSE;
for (i = 0 ; i < DIVISIONS ; i++)
{
for (j = 0 ; j < DIVISIONS ; j++)
{
WinSetWindowULong(WinWindowFromID(hwndMain, (DIVISIONS*i+j)), 0, 0);
}
}
WinInvalidateRect(hwndMain, NULL, TRUE);
WinEnableMenuItem(hwndMenu, IDM_FILESTART, TRUE);
}