/* ********************************************************** 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 ***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; } 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); } return (msg.wParam); } 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; } 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_CLOSE: /* 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); return DefWindowProc (hWnd, iMessage, wParam, lParam); default: return DefWindowProc (hWnd, iMessage, wParam, lParam); } return 0L; } /* 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; { DDEDATA FAR * lpData; char szData[20]; /* If this is good data */ if (iMessage == DDE_DATA) { /* Move data to a local string */ lpData = (DDEDATA FAR *) 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++; } return NULL; } /* 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; { DDEDATA FAR * lpData; char szData[20]; /* If this is good data */ if (iMessage == DDE_DATA) { /* Move data to a local string */ lpData = (DDEDATA FAR *) GlobalLock (hData); lstrcpy (szData, lpData->Value); GlobalUnlock (hData); /* Fish out sub position */ sscanf (szData, "%d %d", &gxSub, &gySub); } return NULL; } /* 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; } } /* 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; } } /* 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); } /* 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; } return TRUE; }