/*++ Copyright (c) 1990 Microsoft Corporation Module Name: Mandel.c Abstract: Win32 application to demo multi-threded app. Author: Mike Hawash@Compaq (o-mikeh), 08-Mar-1992 Environment: Win32 Revision History: 08-Mar-1992 Initial version --*/ //#include //#include //#include //#include //#include //#include // // set variable to define global variables // #include #include #include #include #include "calc.h" /* Defines a complex point */ #include "mandel.h" /* Specific to this program */ #include "remote.h" #define MENUNAME "MandelMenu" #define CLASSNAME "MandelClass" #define ABOUTBOX "AboutBox" #define SAVEBOX "SAVEBOX" char szClassName[50]; #define POLL_TIME 100 #define LINES 4 #define UNREFERENCED(h) (void)h LONG FAR PASCAL MainWndProc(HWND , unsigned , WORD, LONG); void SetNewCalc( CPOINT cptUL, double dPrec, RECT rc); char szTitle[] = "Mandelbrot Fun"; char szBitmap[] = "Mandel"; HANDLE hInst; /* current instance */ extern CPOINT cptUL; extern double dPrec; ULONG gulMaxThreads=1; HANDLE ThrdHandles[MAXTHREADS]; THREADTABLE ThrdTable [MAXTHREADS]; void WorkThread(HWND *phwnd); /*++ main () --*/ int _CRTAPI1 main(USHORT argc, CHAR **argv) /*++ Routine Description: Windows entry point routine Arguments: Return Value: status of operation Revision History: 03-21-91 Initial code --*/ { HANDLE hInstance; HANDLE hPrevInstance = (HANDLE)NULL; LPSTR lpCmdLine; INT nCmdShow = SW_SHOWDEFAULT; USHORT _argc = argc; CHAR **_argv = argv; MSG msg; if (argc==2) gulMaxThreads = min (atoi(argv[1]), MAXTHREADS); sprintf (szClassName, CLASSNAME ": %d", gulMaxThreads); // // check for other instances of this program // hInstance = GetModuleHandle("MANDEL"); // // init shared data and check return value // if (!InitApplication(hInstance)) { DbgPrint("Init application failed\n"); return (FALSE); } // // Acquire and dispatch messages until a WM_QUIT message is received. // while (GetMessage(&msg, // message structure (HWND)NULL, // handle of window receiving the message (UINT)NULL, // lowest message to examine (UINT)NULL)) // highest message to examine { TranslateMessage(&msg); // Translates virtual key codes DispatchMessage(&msg); // Dispatches message to window } return (msg.wParam); // Returns the value from PostQuitMessage } BOOL InitApplication(HANDLE hInstance) /*++ Routine Description: Initializes window data and registers window class. Arguments: hInstance - current instance Return Value: status of operation Revision History: 02-17-91 Initial code --*/ { WNDCLASS wc; HWND hWnd; HMENU hMenu; RECT rc; hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDM_MAINMENU)); // // Fill in window class structure with parameters that describe the // main window. // wc.style = CS_DBLCLKS | CS_BYTEALIGNCLIENT; // Class style(s). wc.lpfnWndProc = (WNDPROC)MainWndProc; // Function to retrieve messages for // windows of this class. wc.cbClsExtra = 0; // No per-class extra data. wc.cbWndExtra = 0; // No per-window extra data. wc.hInstance = hInstance; // Application that owns the class. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor((HANDLE)NULL, IDI_APPLICATION); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; // Name of menu resource in .RC file. wc.lpszClassName = CLASSNAME; /* Name used in call to CreateWindow. */ // // Register the window class and return success/failure code. // if (!RegisterClass(&wc)) return 0; /* Initialize Instance; */ // // Save the instance handle in a static variable, which will be used in // many subsequent calls from this application to Windows. // hInst = hInstance; // // Create a main window for this application instance. // hWnd = CreateWindow( CLASSNAME, /* See RegisterClass() call. */ szClassName, // Text for window title bar. WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX, CW_USEDEFAULT, /* Default horizontal position. */ CW_USEDEFAULT, /* Default horizontal position. */ WIDTH, /* Default width. */ HEIGHT, /* Default height. */ (HWND)NULL, // Overlapped windows have no parent. (HMENU)NULL, // Use the window class menu. hInstance, // This instance owns this window. (LPVOID)NULL // Pointer not needed. ); // // If window could not be created, return "failure" // if (!hWnd) { DbgPrint("Window creation failed\n"); return (FALSE); } // // Make the window visible; update its client area; and return "success" // SetMenu (hWnd, hMenu); ShowWindow(hWnd, SW_SHOWDEFAULT); SetFocus (hWnd); UpdateWindow(hWnd); rc.top = rc.left = 0; rc.bottom = HEIGHT-1; rc.right = WIDTH-1; SetNewCalc( cptUL, dPrec, rc); InitThreads (hWnd); return (TRUE); /* Returns the value from PostQuitMessage */ } /* * FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) * * PURPOSE: Processes messages * * MESSAGES: * * WM_COMMAND - application menu (About dialog box) * WM_DESTROY - destroy window * * COMMENTS: * * To process the IDM_ABOUT message, call MakeProcInstance() to get * the current instance address of the About() function, then call * DialogBox to create the box according to the information in the * GENERIC.RC file and turn control over to the About() function. * When it returns, free the intance address. */ static HDC hdcMem; static int height; LONG FAR PASCAL MainWndProc(hWnd, message, wParam, lParam) HWND hWnd; /* window handle */ unsigned message; /* type of message */ DWORD wParam; /* additional information */ LONG lParam; /* additional information */ { FARPROC lpProcAbout; /* pointer to the "About" function */ PAINTSTRUCT ps; HDC hdc; static HBITMAP hbmMem; static int width; RECT rc; static BOOL fRectDefined = FALSE; static BOOL fButtonDown = FALSE; static RECT rcZoom; static POINT pSelected; POINT pMove; int iWidthNew; int iHeightNew; static int miOldLines; double scaling; switch (message) { case WM_CREATE: hdc = GetDC(hWnd); hdcMem = CreateCompatibleDC(hdc); GetWindowRect(hWnd, &rc); width = rc.right - rc.left; height = rc.bottom - rc.top; hbmMem = CreateCompatibleBitmap(hdc, width, height); SelectObject(hdcMem, hbmMem); ReleaseDC(hWnd,hdc); rc.left = rc.top = 0; rc.right = width+1; rc.bottom = height + 1; FillRect(hdcMem, &rc, GetStockObject(WHITE_BRUSH)); // SetTimer(hWnd, 1, POLL_TIME, NULL); // set timer for polls // CheckMenuItem(GetMenu(hWnd), IDM_LOCAL, // fLocalWork ? MF_CHECKED : MF_UNCHECKED); // CheckMenuItem(GetMenu(hWnd), IDM_REMOTE, // fRemoteWork ? MF_CHECKED : MF_UNCHECKED); // CheckMenuItem(GetMenu(hWnd), IDM_4LINES, MF_CHECKED); // miOldLines = IDM_4LINES; break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hdcMem, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); EndPaint(hWnd, &ps); break; case WM_COMMAND: /* message: command from application menu */ switch(wParam) { case IDM_ABOUT: lpProcAbout = MakeProcInstance(About, hInst); DialogBox(hInst, /* current instance */ ABOUTBOX, /* resource to use */ hWnd, /* parent handle */ lpProcAbout); /* About() instance address */ FreeProcInstance(lpProcAbout); break; case IDM_REDRAW: rc.left = rc.top = 0; rc.right = width+1; rc.bottom = height + 1; FillRect(hdcMem, &rc, GetStockObject(WHITE_BRUSH)); InvalidateRect(hWnd, NULL, TRUE); rc.left = rc.top = 0; rc.bottom = height - 1; rc.right = width - 1; SetNewCalc( cptUL, dPrec, rc); fRectDefined = FALSE; SetEvent (hWorkEvent); // DoSomeWork(hWnd, FALSE); break; case IDM_TOP: PostMessage(hWnd, WM_PAINT, NULL, 0L); break; cptUL.real = (double) -2.05; cptUL.imag = (double) 1.4; dPrec = .01; rc.left = rc.top = 0; rc.bottom = height - 1; rc.right = width - 1; SetNewCalc( cptUL, dPrec, rc); fRectDefined = FALSE; // DoSomeWork(hWnd, FALSE); break; case IDM_1LINE: case IDM_2LINES: case IDM_4LINES: case IDM_8LINES: case IDM_16LINES: case IDM_32LINES: CheckMenuItem(GetMenu(hWnd), miOldLines, MF_UNCHECKED); miOldLines = wParam; switch(wParam) { case IDM_1LINE: iLines = 1; break; case IDM_2LINES: iLines = 2; break; case IDM_4LINES: iLines = 4; break; case IDM_8LINES: iLines = 8; break; case IDM_16LINES: iLines = 16; break; case IDM_32LINES: iLines = 32; } CheckMenuItem(GetMenu(hWnd), miOldLines, MF_CHECKED); break; default: /* Lets Windows process it */ return (DefWindowProc(hWnd, message, wParam, lParam)); } break; case WM_PAINTLINE: PaintLine (hWnd, (THREADTABLE *)wParam, hdcMem, height); ((THREADTABLE *)wParam)->iStatus = SS_IDLE; SetEvent (hWorkEvent); // WaitForSingleObject (hReadyPaintEvent); // pPaintTable = (THREADTABLE *)wParam; // SetEvent(hPaintEvent); break; case WM_DESTROY: /* message: window being destroyed */ PostQuitMessage(0); DeleteDC(hdcMem); DeleteObject(hbmMem); break; default: /* Passes it on if unproccessed */ return (DefWindowProc(hWnd, message, wParam, lParam)); } return (0); } /* * FUNCTION: About(HWND, unsigned, WORD, LONG) * * PURPOSE: Processes messages for "About" dialog box * * MESSAGES: * * WM_INITDIALOG - initialize dialog box * WM_COMMAND - Input received * * COMMENTS: * * No initialization is needed for this particular dialog box, but TRUE * must be returned to Windows. * * Wait for user to click on "Ok" button, then close the dialog box. */ BOOL FAR PASCAL About(hDlg, message, wParam, lParam) HWND hDlg; /* window handle of the dialog box */ unsigned message; /* type of message */ WORD wParam; /* message-specific information */ LONG lParam; { // char buf[UNCLEN+20]; int i; int cServerCount; UNREFERENCED(lParam); switch (message) { case WM_INITDIALOG: /* message: initialize dialog box */ // initialize listbox SendDlgItemMessage(hDlg, LBID_SERVERS, LB_RESETCONTENT, 0, 0L); // cServerCount = GetServerCount(); // // for (i = 0; i < cServerCount; i++) // { // GetServerName(i, buf); // SendDlgItemMessage(hDlg, LBID_SERVERS, LB_INSERTSTRING, // -1, (long)(char far *) buf); // } return (TRUE); case WM_COMMAND: /* message: received a command */ if (wParam == IDOK /* "OK" box selected? */ || wParam == IDCANCEL) /* System menu close command? */ { EndDialog(hDlg, TRUE); /* Exits the dialog box */ return (TRUE); } break; } return (FALSE); /* Didn't process a message */ } BOOL FAR PASCAL SaveAsDlgProc(HWND hDlg, unsigned msg, WORD wParam, LONG lParam) { } PTHREAD_START_ROUTINE CalcThread (THREADTABLE *pThrdTable); HANDLE hWorkEvent; HANDLE hPaintReadyEvent; THREADTABLE *pPaintTable; /*++ InitThreads () --*/ BOOL InitThreads(HWND hWnd) { int i; DWORD dwTid; /* For each thread, create a mutex for sync. This thread * has initial ownership of the mutex(s). The Mutex must * be created first, so the thread has to wait for work. */ for (i=0; i< gulMaxThreads; i++) { ThrdTable[i].iStatus = SS_IDLE; ThrdTable[i].hWnd = hWnd; ThrdHandles[i] = ThrdTable[i].hMutex = CreateEvent (NULL, FALSE, FALSE, NULL); ThrdTable[i].iNumber = i; CreateThread (NULL, 0, CalcThread, &ThrdTable[i], 0, &dwTid); } /* Create the woker thread, where it assigns work for the rest * of the world. */ hWorkEvent = CreateEvent(NULL, FALSE, TRUE, NULL); hPaintReadyEvent = CreateEvent(NULL, FALSE, TRUE, NULL); CreateThread (NULL, 0, WorkThread, hWnd, 0, &dwTid); #if 0 /* Now Create the paint thread, and a Mutex for it. The Mutex signals * when the thread can do work, and when its done. The Mutex thread * should be added to the ThrdHandles[]. */ hPaintEvent = CreateEvent(NULL, FALSE, FALSE, NULL); CreateThread (NULL, 0, PaintThread, &pPaintTable, 0, &dwTid); #endif return TRUE; }/* InitThreads */ extern int cPictureID; // picture id, in case we reset in the middle /*++ --*/ struct _x { BYTE bCode; BYTE bNum; WORD sec; WORD msec; WORD min; }; static struct _x xTime[500]; void PerfCount (BYTE bCode, BYTE bNum) { static int i=0; SYSTEMTIME liTime; xTime[i].bCode = bCode; xTime[i].bNum = bNum; GetSystemTime (&liTime); xTime[i].sec = liTime.wSecond; xTime[i++].msec= liTime.wMilliseconds; }/* PerfCount */ /*++ --*/ PTHREAD_START_ROUTINE CalcThread (THREADTABLE *pThrdTable) { int i; while (1) /* BUGBUG: o-mikeh: might have to termintate somehow */ { WaitForSingleObject (pThrdTable->hMutex, -1L); PerfCount (1, pThrdTable->iNumber); /* Do some work here */ MandelCalc (&(pThrdTable->cptLL), &(pThrdTable->rclDraw), pThrdTable->pBuf); PerfCount (2, pThrdTable->iNumber); /* Make sure we're still working on the same picture */ if (pThrdTable->cPicture == cPictureID) { WaitForSingleObject (hPaintReadyEvent, -1L); PerfCount (3, pThrdTable->iNumber); PaintLine (pThrdTable->hWnd, pThrdTable, hdcMem, height); PerfCount (4, pThrdTable->iNumber); SetEvent (hPaintReadyEvent); } else Beep (1000, 5000); PerfCount (5, pThrdTable->iNumber); pThrdTable->iStatus = SS_IDLE; SetEvent (hWorkEvent); } }/* CalcThread */ #if 0 /*++ --*/ PTHREAD_START_ROUTINE PaintThread (THREADTABLE *pPaintTable) { while (TRUE) { WaitForSingleObject (hPaintEvent); // Beep (2000, 1000); /* Do the painting here */ pPaintTable->iStatus = SS_IDLE; /* Done Painting */ SetEvent (hWorkEvent); // SetEvent (hReadyPaintEvent); } }/* PaintThread */ #endif BreakPoint () { }