Last updated: 15. 2.1998, 18: 4
<*/NOWARN:F*> MODULE Multi2; (*--------------------------------------- MULTI2.C --- Multitasking Demo (c) Charles Petzold, 1996 Multi2.mod --- Translation to Stony Brook Modula-2 (c) Peter Stadler, 1997 ---------------------------------------*) IMPORT WINUSER; IMPORT WIN32; IMPORT WINX; IMPORT WINGDI; IMPORT SYSTEM; IMPORT Lib; IMPORT Threads; IMPORT RealMath; VAR cyChar : INTEGER; CONST szAppName = "Multi2"; VAR hwnd : WIN32.HWND; msg : WINUSER.MSG; wc : WINUSER.WNDCLASSEX; TYPE PARAMS = RECORD hwnd : WIN32.HWND; cxClient : INTEGER; cyClient : INTEGER; cyChar : INTEGER; bKill : BOOLEAN; END; PPARAMS = POINTER TO PARAMS; VAR iNext : INTEGER; params1 : PARAMS; params2 : PARAMS; params3 : PARAMS; params4 : PARAMS; ok : BOOLEAN; code : INTEGER; VAR hwndChild : ARRAY[0..3] OF WIN32.HWND; TYPE CHILD = ARRAY[0..5] OF CHAR; CHILDPROC = ARRAY[0..3] OF WIN32.HINSTANCE; CHILDCLASS = ARRAY[0..3] OF CHILD; CONST szChildClass = CHILDCLASS { "Child1", "Child2", "Child3", "Child4" }; VAR MessageThread : Threads.Thread; (*++++*****************************************************************) PROCEDURE MaxInt (a,b : INTEGER) : INTEGER; (**********************************************************************) BEGIN IF(a>b) THEN RETURN a; ELSE RETURN b; END; END MaxInt; (*++++*****************************************************************) PROCEDURE MinInt (a,b : INTEGER) : INTEGER; (**********************************************************************) BEGIN IF(a>b) THEN RETURN b; ELSE RETURN a; END; END MinInt; (**********************************************************************) PROCEDURE CheckBottom (hwnd : WIN32.HWND; cyClient,cyChar : INTEGER; iLine : INTEGER) : INTEGER; (**********************************************************************) BEGIN IF (iLine * cyChar + cyChar > cyClient) THEN WINUSER.InvalidateRect (hwnd, WINX.NIL_RECT, TRUE); WINUSER.UpdateWindow (hwnd); iLine := 0; END; RETURN iLine; END CheckBottom; (* Window 1: Display increasing sequence of numbers *) (* ************************************************ *) (*+++******************************************************************) PROCEDURE Thread1 (pvoid : WIN32.PVOID): CARDINAL; (**********************************************************************) VAR iNum : INTEGER; iLine : INTEGER; szBuffer : ARRAY[0..15] OF CHAR; hdc : WIN32.HDC; pparams : PPARAMS; BEGIN iNum := 0; iLine := 0; pparams := SYSTEM.CAST(PPARAMS,pvoid); WHILE NOT (pparams^.bKill) DO IF (iNum < 0) THEN iNum := 0; END; iLine := CheckBottom (pparams^.hwnd, pparams^.cyClient, pparams^.cyChar, iLine); INC(iNum); WINUSER.wsprintf (szBuffer, "%d", iNum); hdc := WINUSER.GetDC (pparams^.hwnd); WINGDI.TextOut (hdc, 0, iLine * pparams^.cyChar, szBuffer, LENGTH (szBuffer)); WINUSER.ReleaseDC (pparams^.hwnd, hdc); INC(iLine); END; ok := Threads.KillThread(MessageThread,code); IF(ok) THEN RETURN 0; END; END Thread1; <*/PUSH*> %IF WIN32 %THEN <*/CALLS:WIN32SYSTEM*> %ELSE <*/CALLS:WINSYSTEM*> %END (* *) (*++++*****************************************************************) PROCEDURE WndProc1(hwnd : WIN32.HWND; (**********************************************************************) iMsg : WIN32.UINT; wParam : WIN32.WPARAM; lParam : WIN32.LPARAM) : WIN32.LRESULT (* *)[EXPORT] (* *); BEGIN CASE (iMsg) OF | WINUSER.WM_CREATE : params1.hwnd := hwnd; params1.cyChar := WINUSER.HIWORD (WINUSER.GetDialogBaseUnits ()); Threads.CreateThread(MessageThread, Thread1, SYSTEM.ADR(params1), 8192, TRUE); RETURN 0; | WINUSER.WM_SIZE : params1.cyClient := WINUSER.HIWORD (lParam); RETURN 0; | WINUSER.WM_DESTROY : params1.bKill := TRUE; RETURN 0; ELSE RETURN WINUSER.DefWindowProc (hwnd, iMsg, wParam, lParam); END; END WndProc1; <*/POP*> (* Window 2: Display increasing sequence of prime numbers *) (* ****************************************************** *) (*+++******************************************************************) PROCEDURE Thread2 (pvoid : WIN32.PVOID): CARDINAL; (**********************************************************************) VAR iNum : INTEGER; iLine : INTEGER; i : INTEGER; iSqrt : INTEGER; szBuffer : ARRAY[0..15] OF CHAR; hdc : WIN32.HDC; pparams : PPARAMS; BEGIN iNum := 1; iLine := 0; pparams := SYSTEM.CAST(PPARAMS,pvoid); WHILE NOT (pparams^.bKill) DO REPEAT INC(iNum); IF (iNum < 0) THEN iNum := 0; END; iSqrt := VAL(INTEGER,RealMath.sqrt (FLOAT(iNum))); i := 2; LOOP IF (iNum MOD i = 0) THEN EXIT; END; INC(i); IF(i>iSqrt) THEN EXIT; END; END; UNTIL (i > iSqrt); iLine := CheckBottom (pparams^.hwnd, pparams^.cyClient, pparams^.cyChar, iLine); WINUSER.wsprintf (szBuffer, "%d", iNum); hdc := WINUSER.GetDC (pparams^.hwnd); WINGDI.TextOut (hdc, 0, iLine * pparams^.cyChar, szBuffer, LENGTH(szBuffer)); WINUSER.ReleaseDC (pparams^.hwnd, hdc); INC(iLine); END; ok := Threads.KillThread(MessageThread,code); IF(ok) THEN RETURN 0; END; END Thread2; <*/PUSH*> %IF WIN32 %THEN <*/CALLS:WIN32SYSTEM*> %ELSE <*/CALLS:WINSYSTEM*> %END (*++++*****************************************************************) PROCEDURE WndProc2(hwnd : WIN32.HWND; (**********************************************************************) iMsg : WIN32.UINT; wParam : WIN32.WPARAM; lParam : WIN32.LPARAM) : WIN32.LRESULT (* *)[EXPORT] (* *); BEGIN CASE (iMsg) OF | WINUSER.WM_CREATE : params2.hwnd := hwnd; params2.cyChar := WINUSER.HIWORD (WINUSER.GetDialogBaseUnits ()); Threads.CreateThread(MessageThread, Thread2, SYSTEM.ADR(params2), 8192, TRUE); RETURN 0; | WINUSER.WM_SIZE : params2.cyClient := WINUSER.HIWORD (lParam); RETURN 0; | WINUSER.WM_DESTROY : params2.bKill := TRUE; RETURN 0; ELSE RETURN WINUSER.DefWindowProc (hwnd, iMsg, wParam, lParam); END; END WndProc2; <*/POP*> (* Window 3: Display increasing sequence of Fibonacci numbers *) (* *********************************************************- *) (*+++******************************************************************) PROCEDURE Thread3 (pvoid : WIN32.PVOID): CARDINAL; (**********************************************************************) VAR iNum : INTEGER; iLine : INTEGER; iTemp : INTEGER; szBuffer : ARRAY[0..15] OF CHAR; hdc : WIN32.HDC; pparams : PPARAMS; BEGIN iNum := 1; iLine := 0; pparams := SYSTEM.CAST(PPARAMS,pvoid); WHILE NOT (pparams^.bKill) DO IF (iNum < 0) THEN iNum := 0; iNext := 1; END; iLine := CheckBottom (pparams^.hwnd, pparams^.cyClient, pparams^.cyChar, iLine); WINUSER.wsprintf (szBuffer, "%d", iNum); hdc := WINUSER.GetDC (pparams^.hwnd); WINGDI.TextOut (hdc, 0, iLine * pparams^.cyChar, szBuffer, LENGTH (szBuffer)); WINUSER.ReleaseDC (pparams^.hwnd, hdc); iTemp := iNum; iNum := iNext; iNext := iNext+iTemp; INC(iLine); END; ok := Threads.KillThread(MessageThread,code); IF(ok) THEN RETURN 0; END; END Thread3; <*/PUSH*> %IF WIN32 %THEN <*/CALLS:WIN32SYSTEM*> %ELSE <*/CALLS:WINSYSTEM*> %END (*++++*****************************************************************) PROCEDURE WndProc3(hwnd : WIN32.HWND; (**********************************************************************) iMsg : WIN32.UINT; wParam : WIN32.WPARAM; lParam : WIN32.LPARAM) : WIN32.LRESULT (* *)[EXPORT] (* *); BEGIN CASE (iMsg) OF | WINUSER.WM_CREATE : params3.hwnd := hwnd; params3.cyChar := WINUSER.HIWORD (WINUSER.GetDialogBaseUnits ()); Threads.CreateThread(MessageThread, Thread3, SYSTEM.ADR(params3), 8192, TRUE); RETURN 0; | WINUSER.WM_SIZE : params3.cyClient := WINUSER.HIWORD (lParam); RETURN 0; | WINUSER.WM_DESTROY : params3.bKill := TRUE; RETURN 0; ELSE RETURN WINUSER.DefWindowProc (hwnd, iMsg, wParam, lParam); END; END WndProc3; <*/POP*> (* Window 4: Display circles of random radii *) (* ***************************************-- *) (*+++******************************************************************) PROCEDURE Thread4 (pvoid : WIN32.PVOID): CARDINAL; (**********************************************************************) VAR iDiameter : INTEGER; hdc : WIN32.HDC; pparams : PPARAMS; BEGIN pparams := SYSTEM.CAST(PPARAMS,pvoid); WHILE NOT (pparams^.bKill) DO WINUSER.InvalidateRect (pparams^.hwnd, WINX.NIL_RECT, TRUE); WINUSER.UpdateWindow (pparams^.hwnd); iDiameter := SYSTEM.CAST(INTEGER,Lib.RANDOM(1000) REM VAL(CARDINAL,MaxInt(1,MinInt(pparams^.cxClient,pparams^.cyClient)))); hdc := WINUSER.GetDC (pparams^.hwnd); WINGDI.Ellipse (hdc, (pparams^.cxClient - iDiameter) DIV 2, (pparams^.cyClient - iDiameter) DIV 2, (pparams^.cxClient + iDiameter) DIV 2, (pparams^.cyClient + iDiameter) DIV 2); WINUSER.ReleaseDC (pparams^.hwnd, hdc); END; ok := Threads.KillThread(MessageThread,code); IF(ok) THEN RETURN 0; END; END Thread4; <*/PUSH*> %IF WIN32 %THEN <*/CALLS:WIN32SYSTEM*> %ELSE <*/CALLS:WINSYSTEM*> %END (*++++*****************************************************************) PROCEDURE WndProc4(hwnd : WIN32.HWND; (**********************************************************************) iMsg : WIN32.UINT; wParam : WIN32.WPARAM; lParam : WIN32.LPARAM) : WIN32.LRESULT (* *)[EXPORT] (* *); BEGIN CASE (iMsg) OF | WINUSER.WM_CREATE : params4.hwnd := hwnd; params4.cyChar := WINUSER.HIWORD (WINUSER.GetDialogBaseUnits ()); Threads.CreateThread(MessageThread, Thread4, SYSTEM.ADR(params4), 8192, TRUE); RETURN 0; | WINUSER.WM_SIZE : params4.cxClient := WINUSER.LOWORD (lParam); params4.cyClient := WINUSER.HIWORD (lParam); RETURN 0; | WINUSER.WM_DESTROY : params4.bKill := TRUE; RETURN 0; ELSE RETURN WINUSER.DefWindowProc (hwnd, iMsg, wParam, lParam); END; END WndProc4; <*/POP*> (* Main window to create child windows *) (* *********************************-- *) <*/PUSH*> %IF WIN32 %THEN <*/CALLS:WIN32SYSTEM*> %ELSE <*/CALLS:WINSYSTEM*> %END (*++++*****************************************************************) PROCEDURE WndProc (hwnd : WIN32.HWND; (**********************************************************************) iMsg : WIN32.UINT; wParam : WIN32.WPARAM; lParam : WIN32.LPARAM) : WIN32.LRESULT [EXPORT]; VAR hInstance : WIN32.HINSTANCE; i : INTEGER; cxClient : INTEGER; cyClient : INTEGER; wc : WINUSER.WNDCLASSEX; rc : CARDINAL; BEGIN CASE (iMsg) OF | WINUSER.WM_CREATE : hInstance := SYSTEM.CAST(WIN32.HINSTANCE,WINUSER.GetWindowLong (hwnd, WINUSER.GWL_HINSTANCE)); wc.cbSize := SIZE (wc); wc.style := WINUSER.CS_HREDRAW BOR WINUSER.CS_VREDRAW; wc.cbClsExtra := 0; wc.cbWndExtra := 0; wc.hInstance := hInstance; wc.hIcon := NIL; wc.hCursor := WINUSER.LoadCursor (NIL, WINUSER.IDC_ARROW^); wc.hbrBackground := SYSTEM.CAST(WIN32.HBRUSH, WINGDI.GetStockObject (WINGDI.WHITE_BRUSH)); wc.lpszMenuName := NIL; wc.hIconSm := NIL; FOR i := 0 TO 4-1 DO wc.lpfnWndProc := SYSTEM.CAST(WINUSER.WNDPROC,ChildProc[i]); wc.lpszClassName := SYSTEM.ADR(szChildClass[i]); rc := WINUSER.RegisterClassEx(wc); hwndChild[i] := WINUSER.CreateWindow (szChildClass[i], "", WINUSER.WS_CHILDWINDOW BOR WINUSER.WS_BORDER BOR WINUSER.WS_VISIBLE, 0, 0, 0, 0, hwnd, SYSTEM.CAST(WIN32.HMENU,i), hInstance, NIL); END; cyChar := WINUSER.HIWORD (WINUSER.GetDialogBaseUnits ()); WINUSER.SetTimer (hwnd, 1, 10, NIL); RETURN 0; | WINUSER.WM_SIZE : cxClient := WINUSER.LOWORD (lParam); cyClient := WINUSER.HIWORD (lParam); FOR i := 0 TO 4-1 DO IF(i>1) THEN WINUSER.MoveWindow (hwndChild[i], (i REM 2) * cxClient DIV 2, 1 * cyClient DIV 2, cxClient DIV 2, cyClient DIV 2, TRUE); ELSE WINUSER.MoveWindow (hwndChild[i], (i REM 2) * cxClient DIV 2, 0, cxClient DIV 2, cyClient DIV 2, TRUE); END; END; RETURN 0; | WINUSER.WM_CHAR : IF (wParam = 27) (* '\x1B'*) THEN WINUSER.DestroyWindow (hwnd); END; RETURN 0; | WINUSER.WM_DESTROY : WINUSER.KillTimer (hwnd, 1); WINUSER.PostQuitMessage (0); RETURN 0; ELSE RETURN WINUSER.DefWindowProc (hwnd, iMsg, wParam, lParam); END; END WndProc; <*/POP*> (*++++*****************************************************************) PROCEDURE InitApplication () : BOOLEAN; (**********************************************************************) VAR rc : CARDINAL; BEGIN wc.cbSize := SIZE(wc); wc.style := WINUSER.CS_HREDRAW BOR WINUSER.CS_VREDRAW; wc.lpfnWndProc := WndProc; wc.cbClsExtra := 0; wc.cbWndExtra := 0; wc.hInstance := WINX.Instance; wc.hIcon := WINUSER.LoadIcon (NIL, WINUSER.IDI_APPLICATION^); wc.hCursor := WINUSER.LoadCursor (NIL, WINUSER.IDC_ARROW^); wc.hbrBackground := SYSTEM.CAST(WIN32.HBRUSH, WINGDI.GetStockObject (WINGDI.WHITE_BRUSH)); wc.lpszMenuName := NIL; wc.lpszClassName := SYSTEM.ADR(szAppName); wc.hIconSm := WINUSER.LoadIcon (NIL,WINUSER.IDI_APPLICATION^); rc := WINUSER.RegisterClassEx(wc); RETURN rc#0; END InitApplication; (*++++*****************************************************************) PROCEDURE InitMainWindow () : BOOLEAN; (**********************************************************************) BEGIN hwnd := WINUSER.CreateWindow ( szAppName, (* window class name *) "Multitasking Demo: Translation to Stony Brook Modula-2", (* window caption *) WINUSER.WS_OVERLAPPEDWINDOW, (* window style *) WINUSER.CW_USEDEFAULT, (* initial x position *) WINUSER.CW_USEDEFAULT, (* initial y position *) WINUSER.CW_USEDEFAULT, (* initial x size *) WINUSER.CW_USEDEFAULT, (* initial y size *) NIL, (* parent window handle *) NIL, (* window menu handle *) wc.hInstance, (* program instance handle *) NIL); (* creation parameters *) IF hwnd = NIL THEN RETURN FALSE; END; WINUSER.ShowWindow (hwnd, WINUSER.SW_SHOWDEFAULT); WINUSER.UpdateWindow (hwnd); RETURN TRUE; END InitMainWindow; CONST ChildProc = CHILDPROC { SYSTEM.CAST(WIN32.HINSTANCE,WndProc1), SYSTEM.CAST(WIN32.HINSTANCE,WndProc2), SYSTEM.CAST(WIN32.HINSTANCE,WndProc3), SYSTEM.CAST(WIN32.HINSTANCE,WndProc4) }; BEGIN Lib.RANDOM(1000); IF InitApplication() AND InitMainWindow() THEN WHILE (WINUSER.GetMessage(msg,NIL,0,0)) DO WINUSER.TranslateMessage(msg); WINUSER.DispatchMessage(msg); END; END; END Multi2.