/* ********************************************************** sub.c - Controls a sub in FISH to shoot fish using DDE Placed in public domain by Horizon Technologies Inc. 1990 ***revision history*** 1 SUB.C 24-Jan-90,15:11:52,`JMH' Initial version 2 SUB.C 29-Jan-90,9:13:06,`JMH' Semi-stable version 3 SUB.C 19-Feb-90,14:43:14,`JMH' Version as of 3/5/90 4 SUB.C 19-Jun-90,10:51:24,`JMH' Version as of 6/25/90 5 SUB.C 25-Jun-90,14:48:12,`JMH' Version as of 6/25/90 6 SUB.C 2-Jul-90,14:15:54,`PRS' Version as of 6/25/90 7 SUB.C 19-Jul-90,9:22:42,`PRS' Version with win.ini regerstered settings 8 SUB.C 12-Sep-90,15:59:04,`JMH' Version 1.3 ***revision history*** ********************************************************** */ #define MAIN #define NOCOMM #include "windows.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "dde.h" #include "ddelib.h" #include "sub.h" /* Undocumented windows functions */ int FAR PASCAL lstrlen (LPSTR); LPSTR FAR PASCAL lstrcpy (LPSTR, LPSTR); LPSTR FAR PASCAL lstrcat (LPSTR, LPSTR); int FAR PASCAL lstrcmp (LPSTR, LPSTR); /* Globals */ static HANDLE ghInstance; static char *gszAppName = "Sub"; static int gxFish, gyFish; static int gxSub, gySub; static int gxPrevFish; static DWORD gdwSampleRate; static DWORD gdwSampleCounter; static HANDLE ghFish; static HANDLE ghSub; static DDECALLBACK glpfnFish; static DDECALLBACK glpfnSub; static FARPROC glpfnAbout; /* Functions */ int PASCAL WinMain (HANDLE, HANDLE, LPSTR, int); long FAR PASCAL SubProc (HWND, unsigned, WORD, LONG); WORD FAR PASCAL Fish (HWND, unsigned, LPSTR, HANDLE); WORD FAR PASCAL Sub (HWND, unsigned, LPSTR, HANDLE); void MoveSub (void); BOOL FAR PASCAL About (HWND, unsigned, WORD, LONG); int PASCAL WinMain (hInstance, hPrevInstance, lpCmdLine, nCmdShow) HANDLE hInstance; HANDLE hPrevInstance; LPSTR lpCmdLine; int nCmdShow; { WNDCLASS wndclass; MSG msg; HWND hWnd; ghInstance = hInstance; if ( !hPrevInstance ) { wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = SubProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon ( hInstance, gszAppName ); wndclass.hCursor = LoadCursor ( NULL, IDC_ARROW ); wndclass.hbrBackground = (HBRUSH) GetStockObject ( WHITE_BRUSH ); wndclass.lpszMenuName = gszAppName; wndclass.lpszClassName = gszAppName; if ( !RegisterClass ( &wndclass ) ) return FALSE; } /* if ! hPrevInstance */ hWnd = CreateWindow ( gszAppName, gszAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL ); if ( !hWnd ) return ( NULL ); ShowWindow ( hWnd, SW_SHOWMINIMIZED ); UpdateWindow ( hWnd ); while ( GetMessage ( &msg, NULL, NULL, NULL ) ) { TranslateMessage ( &msg ); DispatchMessage ( &msg ); } /* while GetMessage */ return ( msg.wParam ); } /* function WinMain */ long FAR PASCAL SubProc (hWnd, iMessage, wParam, lParam) HWND hWnd; unsigned iMessage; WORD wParam; LONG lParam; { DDEADVISE ddeAdvise; PAINTSTRUCT ps; char szText[40]; switch ( iMessage ) { case WM_CREATE: /* Provide callback addresses for DDE callback functions */ glpfnFish = (DDECALLBACK) MakeProcInstance ( (FARPROC) Fish, ghInstance ); glpfnSub = (DDECALLBACK) MakeProcInstance ( (FARPROC) Sub, ghInstance ); /* Inititate DDE Sessions with FISH */ if ( !( ghFish = DDEInitiate ( hWnd, "Fish", "Position" ) ) ) break; if ( !( ghSub = DDEInitiate ( hWnd, "Fish", "Sub" ) ) ) break; /* Ask to be advised everytime fish number zero makes a move */ ddeAdvise.fDeferUpd = FALSE; ddeAdvise.fAckReq = TRUE; ddeAdvise.cfFormat = CF_TEXT; DDEAdvise ( ghFish, "0", &ddeAdvise, glpfnFish ); /* Set up a timer to determine the sampling rate */ SetTimer ( hWnd, NULL, 5000, NULL ); break; case WM_COMMAND: switch ( wParam ) { case IDM_EXIT: SendMessage ( hWnd, WM_CLOSE, 0, 0L ); break; case IDM_ABOUT: glpfnAbout = MakeProcInstance ( About, ghInstance ); DialogBox ( ghInstance, "About", hWnd, glpfnAbout ); FreeProcInstance ( glpfnAbout ); break; } /* switch wParam */ break; case WM_PAINT: BeginPaint ( hWnd, &ps ); /* Print the sampling rate */ sprintf ( szText, "Sample rate: %ld/minute, %ld/second", gdwSampleRate, gdwSampleRate / 60 ); TextOut ( ps.hdc, 0, 0, szText, strlen ( szText ) ); sprintf ( szText, "Message rate: %ld/minute, %ld/second", gdwSampleRate * 7, gdwSampleRate * 7 / 60 ); TextOut ( ps.hdc, 0, 20, szText, strlen ( szText ) ); EndPaint ( hWnd, &ps ); break; case WM_TIMER: /* Reset the sample rate counter */ gdwSampleRate = gdwSampleCounter * 12; gdwSampleCounter = 0; /* Cause a repainting of the client area */ InvalidateRect ( hWnd, NULL, TRUE ); UpdateWindow ( hWnd ); break; case WM_DESTROY: /* Cancel the advise circuit for fish zero */ // DDEUnadvise (ghFish, "0"); - BUG: FISH does not ack the unadvise /* End the sessions with FISH */ DDETerminate ( ghFish ); DDETerminate ( ghSub ); PostQuitMessage ( 0 ); break; default: return DefWindowProc ( hWnd, iMessage, wParam, lParam ); } /* switch iMessage */ return 0L; } /* function SubProc */ /* Callback routine to notify us when the fish moves */ WORD FAR PASCAL Fish (hFish, iMessage, lpszItem, hData) HWND hFish; unsigned iMessage; LPSTR lpszItem; HANDLE hData; { LPDDEDATA lpData; char szData[20]; /* If this is good data */ if ( iMessage == DDE_DATA ) { /* Move data to a local string */ lpData = (LPDDEDATA) GlobalLock ( hData ); lstrcpy ( szData, lpData->Value ); GlobalUnlock ( hData ); /* Save the previous x-position of Fish zero */ gxPrevFish = gxFish; /* Fish out new fish position */ sscanf ( szData, "%d %d", &gxFish, &gyFish ); /* Request the current position of the sub */ DDERequest ( ghSub, "Position", CF_TEXT, glpfnSub ); /* Go get the fish that moved */ MoveSub (); /* Show a sample hit */ gdwSampleCounter++; } /* if iMessage */ return NULL; } /* function Fish */ /* Callback routine to notify us of the current sub position */ WORD FAR PASCAL Sub (hSub, iMessage, lpszItem, hData) HWND hSub; unsigned iMessage; LPSTR lpszItem; HANDLE hData; { LPDDEDATA lpData; char szData[20]; /* If this is good data */ if ( iMessage == DDE_DATA ) { /* Move data to a local string */ lpData = (LPDDEDATA) GlobalLock ( hData ); lstrcpy ( szData, lpData->Value ); GlobalUnlock ( hData ); /* Fish out sub position */ sscanf ( szData, "%d %d", &gxSub, &gySub ); } /* if iMessage */ return NULL; } /* function Sub */ /* Function to compute execute command and do it */ void MoveSub () { HANDLE hCommand; LPSTR lpszCommand; BOOL bFire = TRUE; /* Allocate room for the command */ hCommand = GlobalAlloc ( GHND | GMEM_DDESHARE, (DWORD) 10 ); lpszCommand = GlobalLock ( hCommand ); /* Fish is moving right... */ if ( gxFish > gxPrevFish ) { /* We are behind the fish, go get it! */ if ( gxFish > gxSub + 100 ) lstrcpy ( lpszCommand, "[r]" ); /* Can't fire... too close... back away */ else { lstrcpy ( lpszCommand, "[l]" ); bFire = FALSE; } /* else */ } /* if gxFish */ /* Fish is moving left... */ else { /* We are behind the fish, go get it! */ if ( gxFish < gxSub - 100 ) lstrcpy ( lpszCommand, "[l]" ); /* Can't fire... too close... back away */ else { lstrcpy ( lpszCommand, "[r]" ); bFire = FALSE; } /* else */ } /* else */ /* Compute simple up/down command */ lstrcat ( lpszCommand, ( gyFish < gySub ) ? "[u]" : "[d]" ); /* Check for vertical accuracy, cancel fire if too high or low */ if ( abs ( gyFish - gySub ) > 10 ) bFire = FALSE; /* Add the command to Fire! */ if ( bFire ) lstrcat ( lpszCommand, "[f]" ); /* Clean up */ GlobalUnlock ( hCommand ); /* Execute the command */ DDEExecute ( ghSub, hCommand ); } /* function MoveSub */ /* About box */ BOOL FAR PASCAL About (hDlg, iMessage, wParam, lParam) HWND hDlg; unsigned iMessage; WORD wParam; LONG lParam; { switch ( iMessage ) { case WM_INITDIALOG: break; case WM_COMMAND: EndDialog ( hDlg, FALSE ); break; default: return FALSE; } /* switch iMessage */ return TRUE; } /* function About */