ENVIRONMENTS CHARLES PETZOLD Vol. 9, No. 11 --------------------------------------------------------- THREADS2.C -- Demonstrates drawing from a second thread (c) 1990, Ziff Communications Co. PC Magazine * Charles Petzold, 1/90 --------------------------------------------------------- #define INCL_WIN #define INCL_GPI #include #include #define STACKSIZE 4096 * sizeof (int) typedef struct { HPS hps ; BOOL fContinue ; BOOL fTerminate ; SHORT cxClient ; SHORT cyClient ; ULONG semTriggerDraw ; ULONG semDoingDraw ; } THREADPARAMS ; MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ; VOID FAR SecondThread (THREADPARAMS *) ; VOID DrawPattern (HPS, SHORT, SHORT, BOOL *) ; VOID DrawLine (HPS, SHORT, SHORT, SHORT, SHORT) ; HAB hab ; int main (void) { static CHAR szClientClass [] = "Threads2" ; static ULONG flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER | FCF_MINMAX | FCF_SHELLPOSITION | FCF_TASKLIST ; HMQ hmq ; HWND hwndFrame, hwndClient ; QMSG qmsg ; hab = WinInitialize (0) ; hmq = WinCreateMsgQueue (hab, 0) ; WinRegisterClass (hab, szClientClass, ClientWndProc, CS_SIZEREDRAW, 0) ; hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE, &flFrameFlags, szClientClass, NULL, 0L, NULL, 0, &hwndClient) ; while (WinGetMsg (hab, &qmsg, NULL, 0, 0)) WinDispatchMsg (hab, &qmsg) ; WinDestroyWindow (hwndFrame) ; WinDestroyMsgQueue (hmq) ; WinTerminate (hab) ; return 0 ; } MRESULT EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { static int aiThreadStack [STACKSIZE / sizeof (int)] ; static THREADPARAMS tp ; HDC hdc ; SIZEL sizl ; switch (msg) { case WM_CREATE: // create a presentation space for the window hdc = WinOpenWindowDC (hwnd) ; sizl.cx = 0 ; sizl.cy = 0 ; tp.hps = GpiCreatePS (hab, hdc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC) ; // start the thread after initialization tp.fTerminate = FALSE ; DosSemSet (&tp.semTriggerDraw) ; DosSemClear (&tp.semDoingDraw) ; if (_beginthread (SecondThread, aiThreadStack, STACKSIZE, &tp) == -1) { WinMessageBox (HWND_DESKTOP, hwnd, "Cannot create second thread!", "Threads2", 0, MB_OK | MB_ICONEXCLAMATION) ; return 0 ; } return 0 ; case WM_SIZE: // stop the thread from drawing tp.fContinue = FALSE ; DosSemWait (&tp.semDoingDraw, SEM_INDEFINITE_WAIT) ; tp.cxClient = SHORT1FROMMP (mp2) ; tp.cyClient = SHORT2FROMMP (mp2) ; return 0 ; case WM_PAINT: // stop the thread from drawing tp.fContinue = FALSE ; DosSemWait (&tp.semDoingDraw, SEM_INDEFINITE_WAIT) ; // erase the whole window WinInvalidateRect (hwnd, NULL, FALSE) ; WinBeginPaint (hwnd, tp.hps, NULL) ; GpiErase (tp.hps) ; WinEndPaint (tp.hps) ; // let the thread start again at the beginning tp.fContinue = TRUE ; DosSemSet (&tp.semDoingDraw) ; DosSemClear (&tp.semTriggerDraw) ; return 0 ; case WM_DESTROY: // stop the thread and clean up tp.fTerminate = TRUE ; tp.fContinue = FALSE ; DosSemWait (&tp.semDoingDraw, SEM_INDEFINITE_WAIT) ; GpiDestroyPS (tp.hps) ; return 0 ; } return WinDefWindowProc (hwnd, msg, mp1, mp2) ; } VOID _CDECL FAR SecondThread (THREADPARAMS * ptp) { HAB hab ; hab = WinInitialize (0) ; while (!ptp->fTerminate) { // wait for the semaphore to be cleared DosSemWait (&ptp->semTriggerDraw, SEM_INDEFINITE_WAIT) ; // draw the pattern until stopped while (ptp->fContinue) DrawPattern (ptp->hps, ptp->cxClient, ptp->cyClient, &ptp->fContinue) ; DosSemSet (&ptp->semTriggerDraw) ; DosSemClear (&ptp->semDoingDraw) ; } WinTerminate (hab) ; _endthread () ; } VOID DrawPattern (HPS hps, SHORT cxClient, SHORT cyClient, BOOL *pfContinue) { SHORT x, y ; GpiSetMix (hps, FM_INVERT) ; for (x = 0 ; *pfContinue && x < cxClient ; x++) DrawLine (hps, 0, 0, x, cyClient) ; for (y = cyClient ; *pfContinue && y > 0 ; y--) DrawLine (hps, 0, 0, cxClient, y) ; for (y = 0 ; *pfContinue && y < cyClient ; y++) DrawLine (hps, cxClient, 0, 0, y) ; for (x = 0 ; *pfContinue && x < cxClient ; x++) DrawLine (hps, cxClient, 0, x, cyClient) ; for (x = cxClient ; *pfContinue && x > 0 ; x--) DrawLine (hps, cxClient, cyClient, x, 0) ; for (y = 0 ; *pfContinue && y < cyClient ; y++) DrawLine (hps, cxClient, cyClient, 0, y) ; for (y = cyClient ; *pfContinue && y > 0 ; y--) DrawLine (hps, 0, cyClient, cxClient, y) ; for (x = cxClient ; *pfContinue && x > 0 ; x--) DrawLine (hps, 0, cyClient, x, 0) ; } VOID DrawLine (HPS hps, SHORT x1, SHORT y1, SHORT x2, SHORT y2) { POINTL ptl ; ptl.x = x1 ; ptl.y = y1 ; GpiMove (hps, &ptl) ; ptl.x = x2 ; ptl.y = y2 ; GpiLine (hps, &ptl) ; }