home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Phoenix CD 2.0
/
Phoenix_CD.cdr
/
01e
/
msjall.zip
/
MSJV2-5.ZIP
/
MAZE.ALL
next >
Wrap
Text File
|
1987-12-27
|
30KB
|
1,246 lines
Microsoft Systems Journal
Volume 2; Issue 5; November, 1987
Code Listings For:
MAZE
pp. 13-38
Author(s): Kevin P. Welch
Title: Interprogram COmmunications Using Winows' Dynamic Data Exchange
Figure 12
=========
CFLAGS=-c -u -AS -FPa -Gsw -Os -Zep
maze.obj: maze.h maze.c
cl $(CFLAGS) maze.c
maze.exe: maze.obj maze.def maze.lnk
link4 @maze.lnk
Figure 13
=========
NAME Maze
DESCRIPTION 'Dynamic Data Exchange Maze'
STUB '\BIN\WINSTUB.EXE'
CODE MOVEABLE
DATA MOVEABLE MULTIPLE
HEAPSIZE 2048
STACKSIZE 2048
EXPORTS
MazeWndFn @1
Figure 14
=========
maze /align:16
maze
maze
slibw
maze.def
Figure 15
=========
/*
* DDE MAZE - HEADER FILE
*
* LANGUAGE : Microsoft C
* MODEL : Small
* STATUS : Operational
*
* 09/22/87 - Kevin P. Welch - initial creation.
*
*/
#define MAZE_COLS 3
#define MAZE_ROWS 5
#define SC_GRAB_BALL 0x0100
#define SC_GRAB_FOCUS 0x0101
#define HI HIWORD(lPrm)
#define LO LOWORD(lPrm)
#define RGB_BLACK RGB(0x00,0x00,0x00)
#define RGB_WHITE RGB(0xFF,0xFF,0xFF)
/*
* BALL DATA STRUCTURE DEFINITIONS
*
*/
#define BALL_WIDTH 6
#define BALL_HEIGHT 6
#define RANDOM_MOTION (((rand()%2)*2)-1)
#define H_BOUNCE(a,b) ((a<=0)?1:((a>=b)?-1:Ball.iHorzMotion))
#define V_BOUNCE(a,b) ((a<=0)?1:((a>=b)?-1:Ball.iVertMotion))
#define ADVISE_OFF (!Link[i].bAdviseBall)
#define OUTSIDE_LEFT (Ball.rPosn.left<=Link[i].rHole.left)
#define OUTSIDE_RIGHT (Link[i].rHole.right<=Ball.rPosn.right)
#define OUTSIDE_TOP (Ball.rPosn.top<=Link[i].rHole.top)
#define OUTSIDE_BOTTOM (Link[i].rHole.bottom<=Ball.rPosn.bottom)
#define OUTSIDE_WIDTH ((OUTSIDE_LEFT)||(OUTSIDE_RIGHT))
#define OUTSIDE_HEIGHT ((OUTSIDE_TOP)||(OUTSIDE_BOTTOM))
#define OUTSIDE_HOLE ((ADVISE_OFF)||(OUTSIDE_WIDTH)||(OUTSIDE_HEIGHT))
typedef struct {
RECT rPosn; /* current ball position */
long lTimeIn; /* time ball entered maze */
int iHorzMotion; /* vertical ball motion offset */
int iVertMotion; /* horizontal ball motion offset */
BOOL bIsBouncing; /* ball bouncing flag */
} BALL;
/*
* MAZE DATA STRUCTURE DEFINITIONS
*
*/
#define DISPLAY_WIDTH (Maze.wWidth+BALL_WIDTH)
#define DISPLAY_HEIGHT (Maze.wHeight+BALL_HEIGHT)
typedef struct {
WORD wNum; /* maze window number */
WORD wLinks; /* number of maze links */
WORD wWidth; /* width of maze client area */
WORD wHeight; /* height of maze client area */
BOOL bInitiate; /* in initiate flag */
BOOL bGrabBall; /* grab the ball flag */
BOOL bGrabFocus; /* grab the focus flag */
WORD wGoingAway; /* maze going away counter */
} MAZE;
/*
* COMMUNICATION LINK DATA STRUCTURE DEFINITIONS
*
*/
#define MAX_LINK 32
#define HOLE_WIDTH 20
#define HOLE_HEIGHT 14
typedef struct {
HWND hWnd; /* client window handle */
WORD wNum; /* client window number */
RECT rHole; /* client hole position */
BOOL bAdviseBall; /* advise client of ball flag */
BOOL bAdviseStat; /* advise client of stats flag */
} LINK;
/*
* DYNAMIC DATA EXCHANGE DEFINITIONS
*
*/
#define ACCEPTED 0x8000
#define REJECTED 0x0000
#define WM_DDE_INITIATE 0x03e0
#define WM_DDE_TERMINATE 0x03e1
#define WM_DDE_ADVISE 0x03e2
#define WM_DDE_UNADVISE 0x03e3
#define WM_DDE_ACK 0x03e4
#define WM_DDE_DATA 0x03e5
#define WM_DDE_REQUEST 0x03e6
#define WM_DDE_POKE 0x03e7
#define WM_DDE_EXECUTE 0x03e8
#define SEND(a,b,c) SendMessage(a,b,hWnd,c)
#define POST(a,b,c) PostMessage(a,b,hWnd,c)
#define DDE_INITIATE(a,b,c) SEND(a,WM_DDE_INITIATE,MAKELONG(b,c))
#define DDE_TERMINATE(a) POST(a,WM_DDE_TERMINATE,0L)
#define DDE_ADVISE(a,b) Advise(a,hWnd,b)
#define DDE_UNADVISE(a,b) POST(a,WM_DDE_UNADVISE,MAKELONG(0,b))
#define DDE_ACK(a,b,c) POST(a,WM_DDE_ACK,MAKELONG(b,c))
#define DDE_DATA(a,b,c,d,e) Transmit(a,hWnd,WM_DDE_DATA,b,c,d,e)
#define DDE_POKE(a,b,c,d,e) Transmit(a,hWnd,WM_DDE_POKE,b,c,d,e)
typedef struct {
WORD fEmpty:12; /* reserved for future use */
WORD fResponse:1; /* in response to request */
WORD fRelease:1; /* release data */
WORD fNoData:1; /* null data handle ok */
WORD fAck:1; /* Ack expected */
WORD cfFormat; /* clipboard data format */
BYTE info[30]; /* data buffer */
} DATA;
typedef DATA * PDATA;
typedef DATA FAR * LPDATA;
Figure 16
=========
/*
* DDE MAZE - FUNCTION DEFINITIONS
*
* LANGUAGE : Microsoft C
* MODEL : Small
* STATUS : Operational
*
* 09/22/87 - Kevin P. Welch - initial creation.
*
*/
VOID BounceBall( HWND );
WORD DestroyMaze( WORD );
ATOM BumpGlobalAtom( ATOM );
BOOL FindLink( WORD *, HWND );
BOOL Advise( HWND, HWND, ATOM );
HWND CreateMaze( HANDLE, HANDLE, WORD );
BOOL Transmit( HWND, HWND, WORD, ATOM, BOOL, LONG, LONG );
LPSTR FAR PASCAL lstrcpy( LPSTR, LPSTR );
LONG FAR PASCAL MazeWndFn( HWND, WORD, WORD, LONG );
Figure 17
=========
/*
* DDE MAZE - SOURCE CODE
*
* LANGUAGE : Microsoft C
* MODEL : Small
* STATUS : Operational
*
* 09/22/87 - Kevin P. Welch - initial creation.
*
* The DDE Maze demonstrates how Dynamic Data Exchange (DDE) can be
* used in multiple server, multiple client conversations. The maze
* supports two distinct data items - one used in passing the animated
* ball between instances of the Maze, the other for reporting vital
* Maze statistics to an interested listener.
*
* Note that the DDE techniques demonstrated in this program are
* a simplification of the general specification. In ALL cases
* where you observe differences between this application and the
* specification, please follow the published protocol.
*
* Special thanks to Ed Fries, Geoff Nichols, and David West as
* they helped me see the forest from the trees!
*
*/
#include <windows.h>
#include "maze.h"
#include "maze.d"
ATOM aWnd; /* window number item */
ATOM aBall; /* bouncing ball topic */
ATOM aGrab; /* grab the ball item */
ATOM aStat; /* statistics item */
ATOM aAnyMaze; /* generic maze atom */
ATOM aThisMaze; /* this maze atom */
MAZE Maze; /* maze data structure */
BALL Ball; /* ball data structure */
LINK Link[MAX_LINK]; /* maze communications link */
/*
* MAZE MAINLINE & MESSAGE PROCESSING LOOP
*
* hInst current instance handle
* hPrevInst previous instance handle
* lpsCmd execution command line string
* wCmdShow initial show-window option
*
* This mainline is responsible for calling the initialization and
* termination routines in addition to processing and distributing
* all incoming messages. Note the revised message processing
* loop used to animate the bouncing ball.
*
*/
WORD PASCAL WinMain( hInst, hPrevInst, lpsCmd, wCmdShow )
HANDLE hInst;
HANDLE hPrevInst;
LPSTR lpsCmd;
WORD wCmdShow;
{
MSG Msg; /* current system message */
HWND hWnd; /* maze window handle */
/* create & initialize maze */
hWnd = CreateMaze( hInst, hPrevInst, wCmdShow );
/* message processing loop */
do {
/* retrieve next message */
if ( Ball.bIsBouncing ) {
if ( PeekMessage(&Msg,NULL,0,0,TRUE) ) {
if ( Msg.message != WM_QUIT ) {
TranslateMessage( &Msg );
DispatchMessage( &Msg );
}
} else
BounceBall( hWnd );
} else
if ( GetMessage(&Msg,NULL,0,0) ) {
TranslateMessage( &Msg );
DispatchMessage( &Msg );
}
} while ( Msg.message != WM_QUIT );
/* destroy maze & exit */
exit( DestroyMaze(Msg.wParam) );
}
/*
* MAZE WINDOW MESSAGE PROCESSING FUNCTION
*
* hWnd window handle
* wMsg window message number
* wPrm additional message info
* lPrm additional message info
*
* This function processes all the messages related to the maze
* window, including all the DDE messages required in order to
* participate in one or more conversations. Note that this
* window function handles DDE messages for both the client and
* the server sides of the conversation!
*
*/
LONG FAR PASCAL MazeWndFn( hWnd, wMsg, wPrm, lPrm )
HWND hWnd;
WORD wMsg;
WORD wPrm;
LONG lPrm;
{
WORD i; /* channel number */
LONG lAck; /* acknowledgement of message */
/* initialization */
lAck = FALSE;
/* process message */
switch( wMsg )
{
case WM_CREATE : /* create window */
/* adjust window position if tileable */
if ( Maze.wNum <= MAZE_ROWS*MAZE_COLS )
MoveWindow(
hWnd,
(Maze.wWidth*((Maze.wNum-1)%MAZE_COLS)),
(Maze.wHeight*((Maze.wNum-1)/MAZE_COLS)),
Maze.wWidth,
Maze.wHeight,
TRUE
);
break;
case WM_SYSCOMMAND : /* system command */
/* process sub-message */
switch( wPrm )
{
case SC_GRAB_BALL :
/* inform all clients */
if ( Maze.bGrabBall ) {
Maze.bGrabBall = FALSE;
for (i=0; i<Maze.wLinks; i++)
DDE_UNADVISE( Link[i].hWnd, aGrab );
} else {
Maze.bGrabBall = TRUE;
for (i=0; i<Maze.wLinks; i++)
DDE_ADVISE( Link[i].hWnd, aGrab );
}
/* update system menu */
CheckMenuItem(
GetSystemMenu(hWnd,FALSE),
SC_GRAB_BALL,
(Maze.bGrabBall)?MF_CHECKED:MF_UNCHECKED
);
break;
case SC_GRAB_FOCUS :
/* adjust state & system menu */
Maze.bGrabFocus = (Maze.bGrabFocus) ? FALSE : TRUE;
CheckMenuItem(
GetSystemMenu(hWnd,FALSE),
SC_GRAB_FOCUS,
(Maze.bGrabFocus)?MF_CHECKED:MF_UNCHECKED
);
break;
default :
lAck = DefWindowProc( hWnd, wMsg, wPrm, lPrm );
break;
}
break;
case WM_GETMINMAXINFO : /* get window size info */
/* set minimum tracking height */
((LPPOINT)lPrm)[3].y = 5 * HOLE_HEIGHT;
break;
case WM_SIZE : /* window being sized */
/* adjust animation statistics */
Ball.lTimeIn = GetCurrentTime();
/* calculate hole adjusted window dimensions */
Maze.wWidth = LOWORD(lPrm) - HOLE_WIDTH;
Maze.wHeight = HIWORD(lPrm) - HOLE_HEIGHT;
/* randomly position all holes */
for ( i=0; i<Maze.wLinks; i++ ) {
Link[i].rHole.left = rand() % Maze.wWidth;
Link[i].rHole.top = rand() % Maze.wHeight;
Link[i].rHole.right = Link[i].rHole.left + HOLE_WIDTH;
Link[i].rHole.bottom = Link[i].rHole.top + HOLE_HEIGHT;
}
/* calculate ball adjusted window dimensions */
Maze.wWidth = LO - BALL_WIDTH;
Maze.wHeight = HI - BALL_HEIGHT;
/* randomly position bouncing ball */
Ball.rPosn.left = rand() % Maze.wWidth;
Ball.rPosn.top = rand() % Maze.wHeight;
Ball.rPosn.right = Ball.rPosn.left + BALL_WIDTH;
Ball.rPosn.bottom = Ball.rPosn.top + BALL_HEIGHT;
/* assign ball movement direction */
Ball.iHorzMotion = RANDOM_MOTION;
Ball.iVertMotion = RANDOM_MOTION;
break;
case WM_PAINT : /* window needs painting */
{
PAINTSTRUCT Region; /* temporary paint structure */
BYTE sInterior[8]; /* temporary text
string */
BeginPaint( hWnd, &Region );
/* draw all holes in window */
for ( i=0; i<Maze.wLinks; i++ ) {
/* select appropriate text & brush colors */
if ( Link[i].bAdviseBall || Link[i].bAdviseStat ) {
SetBkColor( Region.hdc, RGB_BLACK );
SetTextColor( Region.hdc, RGB_WHITE );
SelectObject( Region.hdc, GetStockObject(BLACK_BRUSH) );
} else {
SetBkColor( Region.hdc, RGB_WHITE );
SetTextColor( Region.hdc, RGB_BLACK );
SelectObject( Region.hdc, GetStockObject(WHITE_BRUSH) );
}
/* draw black hole */
Rectangle(
Region.hdc,
Link[i].rHole.left,
Link[i].rHole.top,
Link[i].rHole.right,
Link[i].rHole.bottom
);
if ( Link[i].wNum )
sprintf( sInterior, "%u", Link[i].wNum );
else
strcpy( sInterior, "?" );
DrawText(
Region.hdc,
sInterior,
strlen(sInterior),
&Link[i].rHole,
DT_CENTER|DT_VCENTER|DT_NOCLIP|DT_SINGLELINE
);
}
EndPaint( hWnd, &Region );
}
break;
case WM_CLOSE : /* end it all */
if ( Maze.wLinks ) {
/* pass ball to first interested client */
if ( Ball.bIsBouncing ) {
for (i=0; (i<Maze.wLinks)&&(!Link[i].bAdviseBall); i++);
DDE_DATA(
Link[ (i<Maze.wLinks) ? i : 0 ].hWnd,
aGrab,
FALSE,
(LONG)Maze.wNum,
(LONG)((GetFocus()==hWnd)?TRUE:FALSE)
);
}
/* notify all clients */
for (i=0; i<Maze.wLinks; i++) {
if (Link[i].bAdviseBall) DDE_UNADVISE(Link[i].hWnd,aBall);
if (Link[i].bAdviseStat) DDE_UNADVISE(Link[i].hWnd,aStat);
DDE_TERMINATE( Link[i].hWnd );
}
/* wait till someone pulls the plug */
Maze.wGoingAway = Maze.wLinks;
Maze.wLinks = 0;
Ball.bIsBouncing = FALSE;
SetWindowText( hWnd, "Maze dying..." );
} else
DestroyWindow( hWnd );
break;
case WM_DESTROY : /* end it all! */
PostQuitMessage( 0 );
break;
case WM_DDE_INITIATE : /* initiate DDE conversation */
/* process message if interesting request */
if ( (hWnd!=wPrm)&&(LO==aAnyMaze||LO==aThisMaze)&&(HI==aBall) ) {
/* check if caller already a client */
if ( !FindLink(&i,wPrm) ) {
/* add caller to list of links */
i = Maze.wLinks++;
Link[i].wNum = 0;
Link[i].hWnd = (HWND)wPrm;
Link[i].bAdviseBall = FALSE;
Link[i].bAdviseStat = FALSE;
/* re-add global atoms */
BumpGlobalAtom( HI );
BumpGlobalAtom( aThisMaze );
SEND( wPrm, WM_DDE_ACK, MAKELONG(aThisMaze,HI) );
/* ask caller to become a server also */
if ( (!Maze.bInitiate)&&(LO==aAnyMaze) ) {
Maze.bInitiate = TRUE;
DDE_INITIATE( wPrm, aAnyMaze, aBall );
Maze.bInitiate = FALSE;
}
/* rearrange window & update display */
SEND(hWnd,WM_SIZE,MAKELONG(DISPLAY_WIDTH,DISPLAY_HEIGHT));
InvalidateRect( hWnd, NULL, TRUE );
}
}
break;
case WM_DDE_ADVISE : /* advise client on DDE item */
{
WORD wAnswer; /* answer to advise message */
LPDATA lpData; /* temporary advise structure */
/* initialization */
wAnswer = REJECTED;
/* search for link */
if ( FindLink(&i,wPrm)&&((HI==aGrab)||(HI==aStat)) ) {
lpData = (LPDATA)GlobalLock( LO );
if ( lpData ) {
if ( lpData->cfFormat == CF_TEXT ) {
wAnswer = ACCEPTED;
Link[i].bAdviseBall |= (HI==aGrab);
Link[i].bAdviseStat |= (HI==aStat);
GlobalUnlock( (HANDLE)LO );
GlobalFree( (HANDLE)LO );
InvalidateRect( hWnd, NULL, TRUE );
} else
GlobalUnlock( LO );
}
}
/* respond to message */
DDE_ACK( wPrm, wAnswer, HI );
}
break;
case WM_DDE_UNADVISE : /* stop advising client on DDE item */
{
WORD wAnswer; /* answer to advise message */
LPDATA lpData; /* temporary advise structure */
/* initialization */
wAnswer = REJECTED;
/* search for link */
if ( FindLink(&i,wPrm)&&((HI==aGrab)||(HI==aStat)) ) {
wAnswer = ACCEPTED;
if (HI==aGrab) Link[i].bAdviseBall=FALSE;
if (HI==aStat) Link[i].bAdviseStat=FALSE;
InvalidateRect( hWnd, NULL, TRUE );
}
/* respond to message */
DDE_ACK( wPrm, wAnswer, HI );
}
break;
case WM_DDE_REQUEST : /* client requestion data item */
{
WORD wAnswer; /* answer to advise message */
LPDATA lpData; /* temporary advise structure */
if ( FindLink(&i,wPrm)&&(HI==aStat)&&(LO==CF_TEXT) )
DDE_DATA(
Link[i].hWnd,
aStat,
TRUE,
(Ball.bIsBouncing)?GetCurrentTime()-Ball.lTimeIn:0L,
DISPLAY_WIDTH*(LONG)DISPLAY_HEIGHT
);
else
DDE_ACK( wPrm, REJECTED, HI );
}
break;
case WM_DDE_POKE : /* client providing unsolicited data item */
case WM_DDE_DATA : /* server providing data item */
{
WORD wData1; /* window number */
WORD wData2; /* focus state */
LPDATA lpData; /* temporary advise structure */
BOOL bRespond; /* boolean respond flag */
WORD wResponse; /* response to message */
char sString[30]; /* temporary data string */
/* initialization */
bRespond = TRUE;
wResponse = REJECTED;
/* search for link & check data item */
if ( FindLink(&i,wPrm)&&((HI==aGrab)||(HI==aWnd)) ) {
/* retrieve data - lock may not succeed */
lpData = (LPDATA)GlobalLock( LO );
if ( lpData ) {
/* check format */
if ( lpData->cfFormat == CF_TEXT ) {
/* extract data */
lstrcpy( (LPSTR)sString, lpData->info );
sscanf( sString, "%u\t%u", &wData1, &wData2 );
/* process data */
if ( HI == aGrab ) {
/* grab ball */
Ball.bIsBouncing = TRUE;
Ball.lTimeIn = GetCurrentTime();
if (Maze.bGrabFocus && wData2) SetFocus(hWnd);
/* randomize display */
SEND(
hWnd,
WM_SIZE,
MAKELONG(DISPLAY_WIDTH,DISPLAY_HEIGHT)
);
} else
Link[i].wNum = wData1;
/* Determine if acknowledgement required */
if ( !lpData->fAck ) {
bRespond = FALSE;
GlobalDeleteAtom( HI );
} else
wResponse = ACCEPTED;
/* unlock memory & free if required */
if ( lpData->fRelease ) {
GlobalUnlock( LO );
GlobalFree( LO );
} else
GlobalUnlock( LO );
/* force system to repaint display */
InvalidateRect( hWnd, NULL, TRUE );
} else
GlobalUnlock( LO );
}
}
/* respond to caller */
if (bRespond) DDE_ACK(wPrm,wResponse,HI);
}
break;
case WM_DDE_ACK : /* DDE acknowledgement */
if ( Maze.bInitiate ) {
/* delete atoms - since bumped */
GlobalDeleteAtom( LO );
GlobalDeleteAtom( HI );
/* inform server of window number */
DDE_POKE(
wPrm,
aWnd,
FALSE,
(LONG)Maze.wNum,
(LONG)((GetFocus()==hWnd)?TRUE:FALSE)
);
/* inform server of current advise status */
if ( Maze.bGrabBall )
DDE_ADVISE( wPrm, aGrab );
}
break;
case WM_DDE_TERMINATE : /* end a DDE conversation */
if ( FindLink(&i,wPrm) ) {
/* respond with an unadvise on all items */
if (Link[i].bAdviseBall) DDE_UNADVISE(wPrm,aBall);
if (Link[i].bAdviseStat) DDE_UNADVISE(wPrm,aStat);
/* remove caller from list */
memcpy(&Link[i],&Link[i+1],(Maze.wLinks-i-1)*sizeof(LINK));
Maze.wLinks--;
/* respond with a matching terminate & update display */
DDE_TERMINATE( wPrm );
InvalidateRect( hWnd, NULL, TRUE );
} else
if ( (Maze.wGoingAway)&&(Maze.wGoingAway-- == 1) )
DestroyWindow( hWnd );
break;
default : /* pass on to default */
lAck = DefWindowProc( hWnd, wMsg, wPrm, lPrm );
break;
}
/* return result */
return( lAck );
}
/*
* CREATE DDE MAZE
*
* hInst current instance handle
* hPrevInst previous instance handle
* wCmdShow initial show window command
*
* This function creates and initializes the Maze, including the
* definition of all global atoms. A handle to the maze window is
* returned if the entire process is successful.
*
*/
static HWND CreateMaze( hInst, hPrevInst, wCmdShow )
HANDLE hInst;
HANDLE hPrevInst;
WORD wCmdShow;
{
WORD i; /* temporary loop variable */
HWND hWnd; /* new maze window handle */
HMENU hMenu; /* system menu handle */
WORD wQueue; /* queue length counter */
BOOL bSearch; /* boolean search flag */
BOOL bPresent; /* number present flag */
WNDCLASS WndClass; /* window class structure */
BYTE sCaption[64]; /* current window caption */
/* perform instance specific initialization */
if ( !hPrevInst ) {
Maze.wNum = 1;
Ball.bIsBouncing = TRUE;
Ball.lTimeIn = GetCurrentTime();
memset( &WndClass, 0, sizeof(WNDCLASS) );
WndClass.lpszClassName = (LPSTR)"MazeWindow";
WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
WndClass.lpszMenuName = (LPSTR)NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = MazeWndFn;
WndClass.hInstance = hInst;
WndClass.hIcon = NULL;
WndClass.hbrBackground = (HBRUSH)(COLOR_MENU + 1);
} else {
GetInstanceData( hPrevInst, (NPSTR)&Maze, sizeof(MAZE) );
GetInstanceData( hPrevInst, (NPSTR)Link, MAX_LINK*sizeof(LINK) );
Link[Maze.wLinks++].wNum = Maze.wNum;
bSearch = TRUE;
Maze.wNum = 1;
while ( bSearch ) {
bPresent = FALSE;
for (i=0; i<Maze.wLinks; i++)
if ( Link[i].wNum == Maze.wNum )
bPresent = TRUE;
if ( bPresent )
Maze.wNum++;
else
bSearch = FALSE;
}
Maze.wLinks = 0;
Ball.bIsBouncing = FALSE;
}
/* continue Maze initialization */
if ( hPrevInst || RegisterClass(&WndClass) ) {
/* adjust maze queue length */
wQueue = 42;
while ( !SetMessageQueue(wQueue--) );
/* define caption & initial position */
sprintf( sCaption, "DDE Maze - #%u", Maze.wNum );
Maze.wGoingAway = 0;
Maze.bGrabBall = FALSE;
Maze.bGrabFocus = FALSE;
Maze.wWidth = GetSystemMetrics(SM_CXSCREEN) / MAZE_COLS;
Maze.wHeight = GetSystemMetrics(SM_CYSCREEN) / MAZE_ROWS;
hWnd = CreateWindow(
"MazeWindow", /* class name */
sCaption, /* caption */
WS_OVERLAPPEDWINDOW, /* style */
0, /* x position */
0, /* y position */
0, /* width */
0, /* height */
(HWND)NULL, /* parent window */
(HMENU)NULL, /* menu */
hInst, /* application */
(LPSTR)NULL /* other data */
);
if ( hWnd ) {
/* revise system menu */
hMenu = GetSystemMenu( hWnd, FALSE );
ChangeMenu(hMenu,0,NULL,0,MF_APPEND|MF_SEPARATOR );
ChangeMenu(hMenu,0,"Grab the ball",SC_GRAB_BALL,MF_APPEND);
ChangeMenu(hMenu,0,"Grab the focus",SC_GRAB_FOCUS,MF_APPEND);
/* define global atoms */
sprintf( sCaption, "Maze%u", Maze.wNum );
aAnyMaze = GlobalAddAtom( "Maze" );
aThisMaze = GlobalAddAtom( sCaption );
aBall = GlobalAddAtom( "Ball" );
aWnd = GlobalAddAtom( "Window" );
aGrab = GlobalAddAtom( "Grab" );
aStat = GlobalAddAtom( "Statistics" );
/* initiate DDE conversation on ball */
Maze.bInitiate = TRUE;
DDE_INITIATE( -1, aAnyMaze, aBall );
Maze.bInitiate = FALSE;
/* seed random number & display maze */
srand( hInst );
ShowWindow( hWnd, wCmdShow );
} else
exit( 2 );
} else
exit( 1 );
/* return final result */
return( hWnd );
}
/*
* BOUNCE BALL IN DDE MAZE
*
* hWnd maze window handle
*
* This function animates the DDE Maze by moving the ball around the
* window. If the ball "falls" into a "hole" a DDE message is
* posted to the appropriate client and the ball transferred. In
* addition, various summary statistics are also provided for those
* interested listeners.
*
*/
static VOID BounceBall( hWnd )
HWND hWnd;
{
WORD i; /* client channel number */
HDC hDC; /* temporary display context */
LONG lElapsed; /* elapsed time ball was bouncing */
/* check if ball inside hole */
for ( i=0; (i<Maze.wLinks)&&(OUTSIDE_HOLE); i++ );
/* animate ball if not in hole */
if ( i == Maze.wLinks ) {
hDC = GetDC( hWnd );
/* Note - you could erase the bouncing ball here using an
* InvertRect call with the current ball position. Leaving it
* out results in an interesting visual effect!
*/
Ball.iHorzMotion = H_BOUNCE( Ball.rPosn.left, Maze.wWidth );
Ball.iVertMotion = V_BOUNCE( Ball.rPosn.top, Maze.wHeight );
/* compute new ball position & draw */
Ball.rPosn.top += Ball.iVertMotion;
Ball.rPosn.left += Ball.iHorzMotion;
Ball.rPosn.right += Ball.iHorzMotion;
Ball.rPosn.bottom += Ball.iVertMotion;
InvertRect( hDC, &Ball.rPosn );
ReleaseDC( hWnd, hDC );
} else {
/* pass ball to client */
Ball.bIsBouncing = FALSE;
DDE_DATA(
Link[i].hWnd,
aGrab,
FALSE,
(LONG)Maze.wNum,
(LONG)((GetFocus()==hWnd)?TRUE:FALSE)
);
/* calculate animation statistics */
lElapsed = GetCurrentTime() - Ball.lTimeIn;
/* inform all statistics clients */
for ( i=0; i<Maze.wLinks; i++ )
if ( Link[i].bAdviseStat )
DDE_DATA(
Link[i].hWnd,
aStat,
FALSE,
lElapsed,
DISPLAY_WIDTH*(LONG)DISPLAY_HEIGHT
);
InvalidateRect( hWnd, NULL, TRUE );
}
}
/*
* ADVISE SERVER TO SEND DATA
*
* hToWnd client window handle
* hFromWnd server window handle
* aItem atom representing item
*
* This function enables the calling routine to advise a client window
* regarding a particular item of data. This function assumes that
* the data is to be sent in CF_TEXT format without requiring any
* acknowledgement. A value of TRUE is returned if the function is
* successful.
*
*/
static BOOL Advise( hToWnd, hFromWnd, aItem )
HWND hToWnd;
HWND hFromWnd;
ATOM aItem;
{
/* local variables */
HANDLE hMem; /* temporary memory handle */
LPDATA lpData; /* pointer to data structure */
BOOL bResult; /* result of function */
bResult = FALSE;
/* allocate memory & check if succeeded */
hMem = GlobalAlloc( GHND|GMEM_DDESHARE, (DWORD)sizeof(DATA) );
if ( hMem ) {
/* lock the data - may not suceed with expanded memory */
lpData = (LPDATA)GlobalLock( hMem );
if ( lpData ) {
/* define data structure constants */
lpData->fAck = FALSE;
lpData->fNoData = FALSE;
lpData->cfFormat = CF_TEXT;
/* unlock prior to sending */
GlobalUnlock( hMem );
/* notify server to send data */
bResult = PostMessage(
hToWnd,
WM_DDE_ADVISE,
hFromWnd,
MAKELONG(hMem,aItem)
);
} else
GlobalFree( hMem );
}
/* return result */
return( bResult );
}
/*
* TRANSMIT DDE DATA TO CLIENT
*
* hToWnd destination window handle
* hFromWnd server window handle
* wMsg message number to use
* aItem atom representing data item
* bResp data in response to a request
* l1 first portion data item to send
* l2 second portion data item to send
*
* This function enables the calling routine to transmit data to a
* client window using either a DDE_DATA or DDE_POKE messgae. It is
* assumed that the information is sent in CF_TEXT format and does not
* require the client to respond. A value of TRUE is returned if the
* entire process is successful.
*
*/
static BOOL Transmit( hToWnd, hFromWnd, wMsg, aItem, bResp, l1, l2 )
HWND hToWnd;
HWND hFromWnd;
WORD wMsg;
ATOM aItem;
BOOL bResp;
LONG l1;
LONG l2;
{
/* local variables */
HANDLE hMem; /* temporary memory handle */
LPDATA lpData; /* pointer to data structure */
BOOL bResult; /* boolean result value */
char sString[32]; /* local string variable */
bResult = FALSE;
/* allocate memory & check if succeeded */
hMem = GlobalAlloc( GHND|GMEM_DDESHARE, (DWORD)sizeof(DATA) );
if ( hMem ) {
/* lock the data - may not suceed with expanded memory */
lpData = (LPDATA)GlobalLock( hMem );
if ( lpData ) {
/* define data structure constants */
lpData->fAck = FALSE;
lpData->fRelease = TRUE;
lpData->fResponse = bResp;
lpData->cfFormat = CF_TEXT;
BumpGlobalAtom( aItem );
/* format the data */
sprintf( sString, "%ld\t%ld", l1, l2 );
lstrcpy( lpData->info, (LPSTR)sString );
/* unlock prior to sending */
GlobalUnlock( hMem );
bResult = PostMessage(
hToWnd,
wMsg,
hFromWnd,
MAKELONG(hMem,aItem)
);
} else
GlobalFree( hMem );
}
/* return result */
return( bResult );
}
/*
* DESTROY DDE MAZE
*
* wQuit application exit code
*
* This function destroys all resources consumed by the Maze during
* execution. Included is the removal of all global atoms. A final
* exit code is returned by the function.
*
*/
static WORD DestroyMaze( wQuit )
WORD wQuit;
{
/* remove global atoms */
GlobalDeleteAtom( aAnyMaze );
GlobalDeleteAtom( aThisMaze );
GlobalDeleteAtom( aBall );
GlobalDeleteAtom( aWnd );
GlobalDeleteAtom( aGrab );
GlobalDeleteAtom( aStat );
/* return final exit code */
return( wQuit );
}
/*
* FIND DDE LINK
*
* pwNdx index to link
* hWnd window handle of caller
*
* This function finds the link references by the window handle
* provided. The resulting link is returned to the caller. The
* function returns TRUE if the window handle was found.
*
*/
static BOOL FindLink( pwNdx, hWnd )
WORD * pwNdx;
HWND hWnd;
{
WORD i;
for (i=0; i<Maze.wLinks; i++)
if ( Link[i].hWnd == hWnd ) {
*pwNdx = i;
return( TRUE );
}
return( FALSE );
}
/*
* BUMP GLOBAL ATOM
*
* aAtom atom to bump
*
* This function increments the reference count to the specified
* global atom. It is assumed that the atom supplied is defined and
* valid. The value supplied is returned.
*
*/
static ATOM BumpGlobalAtom( aAtom )
ATOM aAtom;
{
char sName[64];
GlobalGetAtomName( aAtom, sName, sizeof(sName) );
return( GlobalAddAtom(sName) );
}