MANDEL.C
/**************************************************************************** 
                   Microsoft RPC Version 2.0 
           Copyright Microsoft Corp. 1992, 1993, 1994- 1996 
                        mandel Example 
 
    FILE:       mandel.c 
 
    PURPOSE:    Client side of the RPC distributed application 
 
    COMMENTS:   Main code for the Windows Mandelbrot Set distributed 
                drawing program. 
 
****************************************************************************/ 
 
#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h> 
#include <string.h> 
#include <time.h> 
#include <windows.h>      // Required for all Windows applications 
#include <windowsx.h>     // Allow portability from Win16, Win32 
 
#ifdef RPC 
#include "mdlrpc.h"       // header file generated by the MIDL compiler 
#endif 
#include "mandel.h" 
 
 
/* data structures */ 
 
#ifdef RPC 
char szTitle[] = "Mandelbrot RPC"; 
#else 
char szTitle[] = "Mandelbrot Standalone"; 
#endif 
 
CPOINT      cptUL = { (double) -2.05, (double) 1.4 }; 
double      dPrec = (double) .01; 
 
HANDLE      hInst;         // current instance 
HWND        hWND;          // Main window handle 
 
svr_table   SvrTable; 
int         iLines = LINES; 
 
int         fContinueZoom = TRUE; 
int         fZoomIn       = TRUE; 
 
// split current picture into 16 regions 
// zoom on most complex region;  region with most colors represented 
int         Histogram[4][4][NCOLORS+1] = {0}; 
int         ColorCount[4][4] = {0}; 
int         Max[4][4] = {0}; 
 
int         iHistMaxI = 2; 
int         iHistMaxJ = 3; 
 
RECT        rcZoom; 
BOOL        fRectDefined = FALSE; 
 
#ifdef RPC 
int             fBound = FALSE;     // flag indicates whether bound to svr 
unsigned char * pszUuid             = NULL; 
unsigned char pszProtocolSequence[MAXPROTSEQ] = "ncacn_np"; 
unsigned char pszEndpoint[PATHLEN]            = "\\pipe\\mandel"; 
unsigned char * pszOptions          = NULL; 
unsigned char * pszStringBinding; 
unsigned char   pszNetworkAddress[UNCLEN+1] = {'\0'}; 
#endif 
 
/* function prototypes */ 
 
void     DoSomeWork(HWND, BOOL); 
void     InitHistogram(void); 
void     CalcHistogram(int, int, DWORD, DWORD); 
void     PaintLine(HWND, svr_table *, HDC, int); 
void     DrawRect(HWND, PRECT, BOOL, HDC); 
COLORREF MapColor(DWORD, DWORD); 
 
 
/* 
 *  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) 
 * 
 *  PURPOSE: Calls initialization function, processes message loop 
 * 
 *  COMMENTS: 
 * 
 *      Windows recognizes this function by name as the initial entry point 
 *      for the program.  This function calls the application initialization 
 *      routine, if no other instance of the program is running, and always 
 *      calls the instance initialization routine.  It then executes a message 
 *      retrieval and dispatch loop that is the top-level control structure 
 *      for the remainder of execution.  The loop is terminated when a WM_QUIT 
 *      message is received, at which time this function exits the application 
 *      instance by returning the value passed by PostQuitMessage(). 
 * 
 *      If this function must abort before entering the message loop, it 
 *      returns the conventional value NULL. 
 */ 
 
int WINAPI WinMain( 
    HINSTANCE hInstance,            /* current instance         */ 
    HINSTANCE hPrevInstance,        /* previous instance        */ 
    LPSTR lpCmdLine,                /* command line             */ 
    int nCmdShow)                   /* show-window type (open/icon) */ 
{ 
 
    MSG msg; 
 
    UNREFERENCED_PARAMETER(lpCmdLine); 
 
    if (!hPrevInstance)  /* Other instances of app running? */ 
        if (!InitApplication(hInstance))  /* Initialize shared things */ 
            return(FALSE);  /* Exits if unable to initialize */ 
 
    /* Perform initializations that apply to a specific instance */ 
    if (!InitInstance(hInstance, nCmdShow)) 
        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 */ 
                      0,           /* lowest message to examine      */ 
                      0))          /* highest message to examine     */ 
    { 
        TranslateMessage(&msg);    /* Translates virtual key codes   */ 
        DispatchMessage(&msg);     /* Dispatches message to window   */ 
    } 
 
    return(msg.wParam);  /* Returns the value from PostQuitMessage */ 
 
} 
 
 
/* 
 *  FUNCTION: InitApplication(HANDLE) 
 * 
 *  PURPOSE: Initializes window data and registers window class 
 * 
 *  COMMENTS: 
 * 
 *      This function is called at initialization time only if no other 
 *      instances of the application are running.  This function performs 
 *      initialization tasks that can be done once for any number of running 
 *      instances. 
 * 
 *      In this case, we initialize a window class by filling out a data 
 *      structure of type WNDCLASS and calling the Windows RegisterClass() 
 *      function.  Since all instances of this application use the same window 
 *      class, we only need to do this when the first instance is initialized. 
 */ 
 
BOOL InitApplication(HANDLE hInstance)    /* current instance */ 
{ 
 
    WNDCLASS  wc; 
 
    /* Fill in window class structure with parameters that describe the       */ 
    /* main window.                                                           */ 
    wc.style = 0;                       /* 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(hInstance, "RPC_ICON"); 
    wc.hCursor = LoadCursor(0, IDC_ARROW); 
    wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName =  "MandelMenu";    /* Name of menu resource in .RC file. */ 
    wc.lpszClassName = "MandelClass";   /* Name used in call to CreateWindow. */ 
 
    /* Register the window class and return success/failure code. */ 
    return(RegisterClass(&wc)); 
 
} 
 
 
/* 
 *  FUNCTION:  InitInstance(HANDLE, int) 
 * 
 *  PURPOSE:  Saves instance handle and creates main window. 
 * 
 *  COMMENTS: 
 * 
 *      This function is called at initialization time for every instance of 
 *      this application.  This function performs initialization tasks that 
 *      cannot be shared by multiple instances. 
 * 
 *      In this case, we save the instance handle in a static variable and 
 *      create and display the main program window. 
 */ 
 
BOOL InitInstance(HANDLE   hInstance,   /* Current instance identifier.       */ 
                  int      nCmdShow)    /* Param for first ShowWindow() call. */ 
{ 
    HMENU           hMenu; 
    RECT            rc; 
 
    /* Save the instance handle in static variable, which will be used in  */ 
    /* many subsequence calls from this application to Windows.            */ 
    hInst = hInstance; 
 
    /* Create a main window for this application instance.  */ 
    hWND = CreateWindow( 
               "MandelClass",        /* See RegisterClass() call.          */ 
               szTitle,              /* Text for window title bar.         */ 
               WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX, 
               CW_USEDEFAULT,        /* Default horizontal position.       */ 
               CW_USEDEFAULT,        /* Default vertical 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) 
        return(FALSE); 
 
    /* Make the window visible; update its client area; and return "success" */ 
    ShowWindow(hWND, nCmdShow);  /* Show the window                */ 
    UpdateWindow(hWND);          /* Sends WM_PAINT message         */ 
    rc.top = rc.left = 0; 
    rc.bottom = HEIGHT-1; 
    rc.right = WIDTH-1; 
 
    SetNewCalc(cptUL, dPrec, rc); 
    hMenu = GetMenu(hWND); 
 
#ifndef RPC 
    EnableMenuItem(hMenu, IDM_SERVER, MF_GRAYED);  /* disable option */ 
#endif 
 
    return(TRUE);               /* Returns the value from PostQuitMessage */ 
} 
 
 
/* 
 *  FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) 
 * 
 *  PURPOSE:  Processes messages 
 * 
 *  MESSAGES: 
 *      WM_COMMAND    - application menu 
 *      WM_DESTROY    - destroy window 
 * 
 *  COMMENTS: 
 */ 
 
LONG APIENTRY MainWndProc( 
    HWND hWnd,               /* window handle               */ 
    UINT message,            /* type of message             */ 
    UINT wParam,             /* additional information      */ 
    LONG lParam)             /* additional information      */ 
{ 
    DLGPROC lpProc;          /* pointer to the dialog box function */ 
    PAINTSTRUCT ps; 
    HDC hdc; 
    static HDC     hdcMem; 
    static HBITMAP hbmMem; 
    static int     width; 
    static int     height; 
    RECT           rc; 
    static BOOL    fButtonDown = FALSE; 
    static POINT   pSelected; 
    POINT          pMove; 
    int            iWidthNew; 
    int            iHeightNew; 
    static int     miOldLines; 
    double         scaling; 
 
    switch (message) { 
 
    case WM_CREATE: 
 
#ifdef WIN16 
        RpcWinSetYieldInfo (hWnd, FALSE, 0, 0L); // To make TCP/IP happy 
#else 
        PostMessage(hWnd, WM_COMMAND, IDM_BIND, 0L);    // bind to server 
#endif 
 
        if (!InitRemote(hWnd)) 
            return(FALSE); 
 
        InitHistogram(); 
 
        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)); 
 
        CheckMenuItem(GetMenu(hWnd), IDM_4LINES, MF_CHECKED); 
        CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_CHECKED); 
        miOldLines = IDM_4LINES;  // save to uncheck 
        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_BIND: 
 
#ifdef RPC 
            if (Bind(hWnd) != RPC_S_OK) 
                PostMessage(hWnd, WM_DESTROY, 0, 0L); 
#endif 
            break; 
 
        case IDM_ABOUT: 
            lpProc = MakeProcInstance(About, hInst); 
 
            DialogBox(hInst,       // current instance 
                      "AboutBox",  // resource to use 
                      hWnd,        // parent handle 
                      lpProc);     // About() instance address 
 
            FreeProcInstance(lpProc); 
            break; 
 
        case IDM_ZOOMOUT: 
            if (dPrec > (double)MAXPREC)  // don't allow the zoom out 
                break; 
 
            rcZoom.left = WIDTH/4 + (WIDTH/8);  // center square 
            rcZoom.top   = HEIGHT/4 + (HEIGHT/8); 
            rcZoom.right = rcZoom.left + (WIDTH/4); 
            rcZoom.bottom = rcZoom.top + (HEIGHT/4); 
 
            cptUL.real -= (rcZoom.left * dPrec); // inverse of zoom in 
            cptUL.imag += (rcZoom.top * dPrec); 
            iWidthNew = (rcZoom.right - rcZoom.left + 1); 
            iHeightNew = (rcZoom.bottom - rcZoom.top + 1); 
            scaling = ((double) ((iWidthNew > iHeightNew) ? iWidthNew : iHeightNew) / (double) width); 
            dPrec /= scaling; 
 
            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_ZOOMIN:  // zoom in on selected rectangle 
            // if no rectangle, don't zoom in 
            if (!fRectDefined) 
                break; 
 
            if (dPrec < (double)MINPREC)  // don't allow zoom in 
                break; 
 
            DrawRect(hWnd, &rcZoom, TRUE, hdcMem);  // draw new rect 
 
            // calculate new upper-left 
            cptUL.real += (rcZoom.left * dPrec); 
            cptUL.imag -= (rcZoom.top * dPrec); 
 
            iWidthNew = (rcZoom.right - rcZoom.left + 1); 
            iHeightNew = (rcZoom.bottom - rcZoom.top + 1); 
            scaling = ((double) ((iWidthNew > iHeightNew) ? iWidthNew : iHeightNew) / (double) width); 
 
            dPrec *= scaling; 
 
            rc.left = rc.top = 0; 
            rc.bottom = height - 1; 
            rc.right = width - 1; 
 
            SetNewCalc(cptUL, dPrec, rc); 
            IncPictureID(); 
 
            fRectDefined = FALSE; 
            DoSomeWork(hWnd, FALSE); 
            break; 
 
        case IDM_CONTINUOUS:  // continuous zoom in 
            if (fContinueZoom == TRUE) { 
                CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_UNCHECKED); 
                fContinueZoom = FALSE; 
            } 
            else { 
                CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_CHECKED); 
                fContinueZoom = TRUE; 
            } 
            break; 
 
        case IDM_REDRAW: 
            if (fContinueZoom == TRUE) 
                InitHistogram(); 
 
            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; 
            DoSomeWork(hWnd, FALSE); 
            break; 
 
        case IDM_EXIT: 
            DestroyWindow(hWnd); 
            FreeDrawBuffer(); 
            break; 
 
        case IDM_TOP: 
            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); 
            ResetPictureID();  // incremented past original 
 
            fRectDefined = FALSE; 
            DoSomeWork(hWnd, FALSE); 
            break; 
 
        case IDM_1LINE: 
 
        case IDM_2LINES: 
 
        case IDM_4LINES: 
 
            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; 
            } 
 
            CheckMenuItem(GetMenu(hWnd), miOldLines, MF_CHECKED); 
            break; 
 
#ifdef RPC 
        case IDM_PROTSEQ: 
            lpProc = MakeProcInstance(Protseq, hInst); 
            DialogBox(hInst,        // current instance 
                      "ProtseqBox", // resource to use 
                      hWnd,         // parent handle 
                      lpProc);      // Server instance address 
            FreeProcInstance(lpProc); 
            break; 
 
        case IDM_SERVER: 
            lpProc = MakeProcInstance(Server, hInst); 
            DialogBox(hInst,         // current instance 
                      "ServerBox",   // resource to use 
                      hWnd,          // parent handle 
                      lpProc);       // Server  instance address 
            FreeProcInstance(lpProc); 
            break; 
 
        case IDM_ENDPOINT: 
            lpProc = MakeProcInstance(Endpoint, hInst); 
            DialogBox(hInst,        // current instance 
                      "EndpointBox",// resource to use 
                      hWnd,         // parent handle 
                      lpProc);      // Server instance address 
            FreeProcInstance(lpProc); 
            break; 
#endif 
        case IDM_GO: 
                SetTimer(hWnd, 1, POLL_TIME, NULL);  // set timer for polls 
            EnableMenuItem(GetMenu(hWnd), IDM_GO, MF_GRAYED);   // disable GO 
            break; 
 
 
        default:  // Lets Windows process it 
            return(DefWindowProc(hWnd, message, wParam, lParam)); 
 
        } 
 
        break; 
 
    case WM_DESTROY:  // message: window being destroyed 
        PostQuitMessage(0); 
        DeleteDC(hdcMem); 
        DeleteObject(hbmMem); 
        break; 
 
    case WM_DOSOMEWORK:  // do another slice of calculation work 
        DoSomeWork(hWnd, FALSE); 
        break; 
 
    case WM_PAINTLINE:  // The shared buffer contains a line of data; draw it 
        PaintLine(hWnd, 
                  &SvrTable, 
                  hdcMem, 
                  height); 
        break; 
 
    case WM_TIMER:  // timer means we should do another slice of work 
        DoSomeWork(hWnd, TRUE); 
        break; 
 
    case WM_LBUTTONDOWN:  // left button down; start to define a zoom rectangle 
        if (fRectDefined) 
            DrawRect(hWnd, &rcZoom, FALSE, hdcMem);  // undraw old rectangle 
 
        // initialize rectangle 
        rcZoom.left = rcZoom.right = pSelected.x = LOWORD(lParam); 
        rcZoom.top = rcZoom.bottom = pSelected.y = HIWORD(lParam); 
 
        // draw the new rectangle 
        DrawRect(hWnd, &rcZoom, TRUE, hdcMem); 
 
        fRectDefined = TRUE; 
        fButtonDown = TRUE; 
        SetCapture(hWnd);  // capture all mouse events 
        break; 
 
    case WM_MOUSEMOVE:  // mouse move 
        // if the button is down, change the rect 
        if (!fButtonDown) 
            break; 
 
        DrawRect(hWnd, &rcZoom, FALSE, hdcMem);  // undraw old rect 
 
        pMove.x = LOWORD(lParam); 
        pMove.y = HIWORD(lParam); 
 
        // update the selection rectangle 
        if (pMove.x <= pSelected.x) 
            rcZoom.left = pMove.x; 
        if (pMove.x >= pSelected.x) 
            rcZoom.right = pMove.x; 
        if (pMove.y <= pSelected.y) 
            rcZoom.top = pMove.y; 
        if (pMove.y >= pSelected.y) 
            rcZoom.bottom = pMove.y; 
 
        DrawRect(hWnd, &rcZoom, TRUE, hdcMem);  // draw new rect 
        break; 
 
    case WM_LBUTTONUP:  // button up; end selection 
        fButtonDown = FALSE; 
        ReleaseCapture(); 
        break; 
 
    default:  // Passes it on if unproccessed 
        return(DefWindowProc(hWnd, message, wParam, lParam)); 
 
    } 
 
    return(0L); 
} 
 
 
/* 
 *  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 APIENTRY About( 
    HWND hDlg,              /* window handle of the dialog box */ 
    UINT message,           /* type of message                 */ 
    UINT wParam,            /* message-specific information    */ 
    LONG lParam) 
{ 
    UNREFERENCED_PARAMETER(lParam); 
 
    switch (message) { 
 
    case WM_INITDIALOG:     /* message: initialize dialog box  */ 
        return(TRUE); 
 
    case WM_COMMAND:        /* message: received a command     */ 
        if (wParam == IDOK || wParam == IDCANCEL) 
        { 
            EndDialog(hDlg, TRUE);    /* Exits the dialog box  */ 
            return(TRUE); 
        } 
        break; 
    } 
 
    return(FALSE);          /* Didn't process a message        */ 
} 
 
 
 
/* 
 *  FUNCTION: Protseq(HWND, unsigned, WORD, LONG) 
 * 
 *  PURPOSE:  Processes messages for "Protseq" 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 APIENTRY Protseq( 
    HWND hDlg,               /* window handle of the dialog box */ 
    UINT message,            /* type of message             */ 
    UINT wParam,             /* message-specific information    */ 
    LONG lParam) 
{ 
 
    UNREFERENCED_PARAMETER(lParam); 
 
#ifdef RPC 
 
    switch (message) { 
 
    case WM_INITDIALOG:    // message: initialize dialog box 
        SetDlgItemText((HANDLE)hDlg, IDD_PROTSEQNAME, pszProtocolSequence); 
        return(TRUE); 
 
    case WM_COMMAND:       // message: received a command 
        switch(wParam) { 
 
        case IDCANCEL:     // System menu close command? 
            EndDialog(hDlg, FALSE); 
            return(TRUE); 
 
        case IDOK:         // "OK" box selected? 
            GetDlgItemText(hDlg, IDD_PROTSEQNAME, pszProtocolSequence, MAXPROTSEQ); 
 
            if (Bind(hDlg) != RPC_S_OK) { 
                EndDialog(hDlg, FALSE); 
                return(FALSE); 
            } 
                KillTimer(hWND, 1);  // stop timer for polls 
            EnableMenuItem(GetMenu(hWND), IDM_GO, MF_ENABLED);  // enable GO 
 
            EndDialog(hDlg, TRUE); 
            return(TRUE); 
 
        } 
 
    } 
 
#endif 
 
    return(FALSE);  // Didn't process a message 
} 
 
 
/* 
 *  FUNCTION: Server(HWND, unsigned, WORD, LONG) 
 * 
 *  PURPOSE:  Processes messages for "Server" 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 APIENTRY Server( 
    HWND hDlg,               /* window handle of the dialog box */ 
    UINT message,            /* type of message             */ 
    UINT wParam,             /* message-specific information    */ 
    LONG lParam) 
{ 
 
    UNREFERENCED_PARAMETER(lParam); 
 
#ifdef RPC 
 
    switch (message) { 
 
    case WM_INITDIALOG:      /* message: initialize dialog box */ 
        SetDlgItemText(hDlg, IDD_SERVERNAME, pszNetworkAddress); 
        return(TRUE); 
 
    case WM_COMMAND:         /* message: received a command    */ 
        switch(wParam) { 
 
        case IDCANCEL:       /* System menu close command?     */ 
            EndDialog(hDlg, FALSE); 
            return(TRUE); 
 
        case IDOK:            /* "OK" box selected?            */ 
            GetDlgItemText( hDlg, IDD_SERVERNAME, pszNetworkAddress, UNCLEN); 
 
            if (Bind(hDlg) != RPC_S_OK) { 
                EndDialog(hDlg, FALSE); 
                return(FALSE); 
            } 
                KillTimer(hWND, 1);  // stop timer for polls 
            EnableMenuItem(GetMenu(hWND), IDM_GO, MF_ENABLED);  // enable GO 
 
            EndDialog(hDlg, TRUE); 
            return(TRUE); 
        } 
 
    } 
 
#endif 
 
    return(FALSE);           /* Didn't process a message      */ 
 
} 
 
/* 
 *  FUNCTION: Endpoint(HWND, unsigned, WORD, LONG) 
 * 
 *  PURPOSE:  Processes messages for "Endpoint" 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 APIENTRY Endpoint( 
    HWND hDlg,               /* window handle of the dialog box */ 
    UINT message,            /* type of message             */ 
    UINT wParam,             /* message-specific information    */ 
    LONG lParam) 
{ 
 
    UNREFERENCED_PARAMETER(lParam); 
 
#ifdef RPC 
 
    switch (message) { 
 
    case WM_INITDIALOG:    // message: initialize dialog box 
        SetDlgItemText(hDlg, IDD_ENDPOINTNAME, pszEndpoint); 
        return(TRUE); 
 
    case WM_COMMAND:       // message: received a command 
        switch(wParam) { 
 
        case IDCANCEL: 
            EndDialog(hDlg, FALSE); 
            return(TRUE); 
 
        case IDOK: 
            GetDlgItemText(hDlg, IDD_ENDPOINTNAME, pszEndpoint, PATHLEN); 
 
            if (Bind(hDlg) != RPC_S_OK) { 
                EndDialog(hDlg, FALSE); 
                return(FALSE); 
            } 
                KillTimer(hWND, 1);  // stop timer for polls 
            EnableMenuItem(GetMenu(hWND), IDM_GO, MF_ENABLED);  // enable GO 
 
            EndDialog(hDlg, TRUE); 
            return(TRUE); 
 
        } 
 
    } 
 
#endif 
 
    return(FALSE);  // Didn't process a message 
} 
 
 
/* 
 *  DoSomeWork -- 
 * 
 *  This function does our work for us. It does it in little pieces, and 
 *  will schedule itself as it sees fit. 
 */ 
 
void 
DoSomeWork(HWND    hwnd, 
           BOOL    fTimer) 
{ 
    static WORD   wIteration = 0; 
 
    if (fTimer) { 
        wIteration++; 
 
        // on every nth tick, we send out a poll 
        if (wIteration == 120) {  // tune this? 
            wIteration = 0; 
            return; 
        } 
 
        // on the half-poll, we check for responses 
        if ((wIteration == 2) || (wIteration == 10)) { 
            return; 
        } 
    } 
 
    if (CheckDrawStatus(hwnd)) 
        SendMessage(hwnd, WM_DOSOMEWORK, 0, 0L); 
 
    return; 
} 
 
 
/* 
 *  DrawRect -- 
 * 
 *  This function draws (or undraws) the zoom rectangle. 
 */ 
 
void 
DrawRect(HWND      hwnd, 
         PRECT     prc, 
         BOOL      fDrawIt, 
         HDC       hdcBM) 
{ 
    HDC     hdc; 
    DWORD   dwRop; 
 
    hdc = GetDC(hwnd); 
 
    if (fDrawIt) 
        dwRop = NOTSRCCOPY; 
    else 
        dwRop = SRCCOPY; 
 
    // top side 
    BitBlt(hdc, prc->left, prc->top, (prc->right - prc->left) + 1, 
           1, hdcBM, prc->left, prc->top, dwRop); 
 
    // bottom side 
    BitBlt(hdc, prc->left, prc->bottom, (prc->right - prc->left) + 1, 
           1, hdcBM, prc->left, prc->bottom, dwRop); 
 
    // left side 
    BitBlt(hdc,prc->left, prc->top, 1, (prc->bottom - prc->top) + 1, 
           hdcBM, prc->left, prc->top, dwRop); 
 
    // right side 
    BitBlt(hdc,prc->right, prc->top, 1, (prc->bottom - prc->top) + 1, 
           hdcBM, prc->right, prc->top, dwRop); 
 
    ReleaseDC(hwnd, hdc); 
} 
 
 
/* 
 *  PaintLine -- 
 * 
 *  This function paints a buffer of data into the bitmap. 
 */ 
 
void 
PaintLine(HWND        hwnd, 
          svr_table * pst, 
          HDC         hdcBM, 
          int         cHeight) 
{ 
    LPWORD  pwDrawData; 
    int     y; 
    int     x; 
    DWORD   dwThreshold; 
    RECT    rc; 
    WORD    lines; 
 
    lines  = (WORD) pst->cLines; 
 
    // picture ID had better match, or else we skip it 
    if (CheckDrawingID(pst->cPicture)) 
    { 
        // figure out our threshold 
        dwThreshold = QueryThreshold(); 
 
        // get a pointer to the draw buffer 
        pwDrawData = (LPWORD) LockDrawBuffer(); 
        if (pwDrawData == NULL) { 
            ReturnDrawBuffer(); 
            return; 
        } 
 
        // starting x coordinate 
        x = (int) pst->dwLine; 
 
        // now loop through the rectangle 
        while (lines-- > 0) 
        { 
            // bottom to top, since that's the order of the data in the buffer 
            y = (int) cHeight-1; 
 
            while (y >= 0) 
            { 
                // draw a pixel 
                SetPixel(hdcBM, x,y, MapColor(*pwDrawData, dwThreshold)); 
 
                if (fContinueZoom == TRUE) 
                    CalcHistogram(x, y, *pwDrawData, dwThreshold); 
 
                // now increment buffer pointer and y coord 
y--; 
                pwDrawData++; 
            } 
 
            // increment X coordinate 
            x++; 
        } 
 
        // figure out the rectangle to invalidate 
        rc.top = 0; 
        rc.bottom = cHeight; 
        rc.left = (int)(pst->dwLine); 
        rc.right = (int)(pst->dwLine) + pst->cLines; 
 
        UnlockDrawBuffer(); 
 
        // and invalidate it on the screen so we redraw it 
        InvalidateRect(hwnd, &rc, FALSE); 
    } 
 
    // free this for someone else to use 
    ReturnDrawBuffer(); 
 
    // and change the pipe state, if necessary 
    if (pst->iStatus == SS_PAINTING) 
        pst->iStatus = SS_IDLE; 
 
} 
 
 
#define CLR_BLACK       RGB(0,0,0) 
#define CLR_DARKBLUE    RGB(0,0,127) 
#define CLR_BLUE        RGB(0,0,255) 
#define CLR_CYAN        RGB(0,255,255) 
#define CLR_DARKGREEN   RGB(0,127,0) 
#define CLR_GREEN       RGB(0,255,0) 
#define CLR_YELLOW      RGB(255,255,0) 
#define CLR_RED         RGB(255,0,0) 
#define CLR_DARKRED     RGB(127,0,0) 
#define CLR_WHITE       RGB(255,255,255) 
#define CLR_PALEGRAY    RGB(194,194,194) 
#define CLR_DARKGRAY    RGB(127,127,127) 
 
 
static COLORREF ColorMapTable[] = {     // size = NCOLORS 
    CLR_DARKBLUE, 
    CLR_BLUE, 
    CLR_CYAN, 
    CLR_DARKGREEN, 
    CLR_GREEN, 
    CLR_YELLOW, 
    CLR_RED, 
    CLR_DARKRED, 
    CLR_WHITE, 
    CLR_PALEGRAY, 
    CLR_DARKGRAY}; 
 
 
/* 
 *  MapColor -- 
 * 
 *  This function maps an iteration count into a corresponding RGB color. 
 */ 
 
COLORREF 
MapColor(DWORD  dwIter, 
         DWORD  dwThreshold) 
{ 
 
    /* if it's beyond the threshold, call it black */ 
    if (dwIter >= dwThreshold) { 
        return(CLR_BLACK); 
    } 
 
    /* get a modulus based on the number of colors */ 
    dwIter = (dwIter / 3) % NCOLORS; // 11; 
 
    /* and return the appropriate color */ 
    return(ColorMapTable[dwIter]); 
 
} 
 
 
/* 
 * CalcHistogram -- 
 * 
 * This function is used to select the region that is the 
 * most complex and will be used to zoom in for the next picture; 
 * it contains the most colors.  The number of colors are counted. 
 */ 
 
void 
CalcHistogram(int    x, 
              int    y, 
              DWORD  dwIter, 
              DWORD  dwThreshold) 
{ 
 
    /* if it's beyond the threshold, call it black */ 
    if (dwIter >= dwThreshold) { 
        Histogram[x/(WIDTH/4)][y/(HEIGHT/4)][NCOLORS]++; 
        return; 
    } 
 
    /* get a modulus based on the number of colors */ 
    dwIter = (dwIter / 3) % NCOLORS; // 11; 
 
    /* and bump the count for the appropriate color */ 
    Histogram[x/(WIDTH/4)][y/(HEIGHT/4)][dwIter]++;  // region of map 
 
    return; 
 
} 
 
 
/* 
 * InitHistogram -- 
 * 
 * This function initializes the histogram data structures. 
 */ 
 
void InitHistogram(void) 
{ 
    int i, j, k; 
 
    for (i = 0; i < 4; i++) 
        for (j = 0; j < 4; j++) 
            for (k = 0; k <= NCOLORS; k++) 
                Histogram[i][j][k] = 0;  // count of colors 
} 
 
 
/* 
 * CountHistogram -- 
 * 
 * This function determines the number of colors represented 
 * within a region.  The region with the most colors is 
 * selected using the maxi and maxj values.  X and Y coordinates 
 * corresponding to these regions are stored in the HistRegion 
 * table and are used for the next picture. 
 */ 
 
void CountHistogram(void) 
{ 
 
    int i, j, k; 
 
    /* count the number of colors in each region */ 
    /* find the color that dominates each region */ 
    for (i = 0; i < 4; i++) { 
        for (j = 0; j < 4; j++) { 
            ColorCount[i][j] = 0; 
            Max[i][j] = 0; 
            for (k = 0; k <= NCOLORS; k++) { 
                if (Histogram[i][j][k] > Max[i][j]) 
                    Max[i][j] = Histogram[i][j][k]; 
                if (Histogram[i][j][k] != 0)  // count of colors 
                    ColorCount[i][j]++; 
            } 
        } 
    } 
 
    iHistMaxI = 0; 
    iHistMaxJ = 0; 
 
    /* if several regions have the same number of colors,        */ 
    /* select the region with the most variety: the smallest max */ 
    for (i = 0; i < 4; i++) { 
        for (j = 0; j < 4; j++) { 
            if (   (ColorCount[i][j] >= ColorCount[iHistMaxI][iHistMaxJ]) 
                && (Max[i][j] < Max[iHistMaxI][iHistMaxJ]) ) { 
                iHistMaxI = i; 
                iHistMaxJ = j; 
            } 
        } 
    } 
 
    InitHistogram();  // initialize for next time 
 
} 
 
 
#ifdef RPC 
 
void __RPC_FAR * __RPC_API midl_user_allocate(size_t len) 
{ 
    UNREFERENCED_PARAMETER(len); 
    return(NULL); 
} 
 
 
void __RPC_API midl_user_free(void __RPC_FAR * ptr) 
{ 
    UNREFERENCED_PARAMETER(ptr); 
    return; 
} 
 
 
/* 
 *  FUNCTION: Bind(HWND) 
 * 
 *  PURPOSE:  Make RPC API calls to bind to the server application 
 * 
 *  COMMENTS: 
 * 
 *      The binding calls are made from InitInstance() and whenever 
 *      the user changes the server name or endpoint. If the bind 
 *      operation is successful, the global flag fBound is set to TRUE. 
 * 
 *      The global flag fBound is used to determine whether to call 
 *      the RPC API function RpcBindingFree. 
 */ 
 
RPC_STATUS Bind(HWND hWnd) 
{ 
    RPC_STATUS status; 
    char pszFail[MSGLEN]; 
 
    if (fBound == TRUE) {  // unbind only if bound 
        status = RpcStringFree(&pszStringBinding); 
        if (status) { 
            sprintf(pszFail, "RpcStringFree failed 0x%x", status); 
            MessageBox(hWnd, 
                       pszFail, 
                       "RPC Sample Application", 
                       MB_ICONSTOP); 
            return(status); 
        } 
 
        status = RpcBindingFree(&hMandel); 
        if (status) { 
            sprintf(pszFail, "RpcBindingFree failed 0x%x", status); 
            MessageBox(hWnd, 
                       pszFail, 
                       "RPC Sample Application", 
                       MB_ICONSTOP); 
            return(status); 
        } 
 
        fBound = FALSE;  // unbind successful; reset flag 
    } 
 
    status = RpcStringBindingCompose(pszUuid, 
                                     pszProtocolSequence, 
                                     pszNetworkAddress, 
                                     pszEndpoint, 
                                     pszOptions, 
                                     &pszStringBinding); 
    if (status) { 
        sprintf(pszFail, "RpcStringBindingCompose returned: (0x%x)\nNetwork Address = %s\n", 
              status, pszNetworkAddress); 
        MessageBox(hWnd, pszFail, "RPC Sample Application", MB_ICONINFORMATION); 
        return(status); 
    } 
 
    status = RpcBindingFromStringBinding(pszStringBinding, 
                                         &hMandel); 
    if (status) { 
        sprintf(pszFail, "RpcBindingFromStringBinding returned: (0x%x)\nString = %s\n", 
             status, pszStringBinding); 
        MessageBox(hWnd, pszFail, "RPC Sample Application", MB_ICONINFORMATION); 
        return(status); 
    } 
 
    fBound = TRUE;  // bind successful; reset flag 
 
    return(status); 
} 
 
#endif 
 
 
/* end mandel.c */