|
|
1.1 ! root 1: /* ! 2: * REMOTE.C -- ! 3: * ! 4: * Code to do the remote calculations for the Windows Mandelbrot Set ! 5: * distributed drawing program. ! 6: * ! 7: * Copyright (C) 1990 Microsoft Corporation. ! 8: * ! 9: * Information coming into this module (via API calls) is based on ! 10: * upper-left being (0,0) (the Windows standard). We translate that ! 11: * to PM standard (lower-left is (0,0) ) before we ship it out onto ! 12: * the net, and we do reverse translations accordingly. ! 13: * ! 14: * The iteration data is passed back to the main window procedure ! 15: * (by means of a WM_PAINTLINE message) which draws the picture. ! 16: * ! 17: * A word about the shared buffer: multiple buffers could be used, but ! 18: * a single one is used. The buffer is requested in this code, and ! 19: * then released after the data has been drawn (in PaintLine() in ! 20: * mandel.c). So long as the painting is done quickly, this is efficient. ! 21: * ! 22: * This code sample is provided for demonstration purposes only. ! 23: * Microsoft makes no warranty, either express or implied, ! 24: * as to its usability in any given situation. ! 25: */ ! 26: ! 27: ! 28: #include <string.h> ! 29: #include <stdio.h> ! 30: #include <fcntl.h> ! 31: #include <sys\types.h> ! 32: #include <sys\stat.h> ! 33: #include <share.h> ! 34: #include <io.h> ! 35: #include <malloc.h> ! 36: ! 37: #include <windows.h> ! 38: ! 39: #ifdef RPC ! 40: #include <rpc.h> ! 41: #include "mdlrpc.h" ! 42: #endif ! 43: ! 44: #include "mandel.h" ! 45: /* ! 46: * Tuning paramters ! 47: */ ! 48: #define SVR_TABLE_SZ 20 ! 49: #define MAX_PIPENAME_SZ CCHMAXPATH ! 50: ! 51: ! 52: /* ! 53: * Manifests, to keep everything neat. ! 54: */ ! 55: ! 56: extern int errno; // errno from c runtime ! 57: ! 58: /* ! 59: * Data structures ! 60: */ ! 61: extern svr_table SvrTable[]; // the table ! 62: extern int SvrTableSz; // # of objects in it ! 63: char pszFail[255]; ! 64: ! 65: ! 66: // Do we do local work? ! 67: BOOL fLocalWork = TRUE; ! 68: BOOL fRemoteWork = FALSE; ! 69: ! 70: static int fDisplay = TRUE; /* display a message box for debug */ ! 71: ! 72: // Picture information ! 73: ! 74: int cPictureID = 0; // picture id, in case we reset in the middle ! 75: static CPOINT cptLL; // upper-left ! 76: static double dPrecision; // precision of draw ! 77: static LONGRECT rclPicture; // rectangle defining client window ! 78: static DWORD dwCurrentLine; // next line to be drawn ! 79: static DWORD dwThreshold; // threshold for iterations ! 80: ! 81: ! 82: static char szLocal[] = "Local machine"; ! 83: #ifdef RPC ! 84: RPC_STATUS status; // returned by RPC API function ! 85: #endif ! 86: /* ! 87: * function prototypes for local procs ! 88: */ ! 89: ! 90: DWORD CalcThreshold( double ); ! 91: ! 92: ! 93: ! 94: /* ! 95: * InitRemote -- ! 96: * ! 97: * This function initializes everything for our remote connections. ! 98: * It gets the local wksta name (making sure the wksta is started) ! 99: * and it creates the mailslot with which to collect replies to our poll. ! 100: * ! 101: * RETURNS ! 102: * ! 103: * TRUE - initialization succeeded ! 104: * FALSE - initialization failed, can't go on ! 105: */ ! 106: ! 107: ! 108: BOOL ! 109: InitRemote( HWND hWnd ) ! 110: { ! 111: #ifndef RPC ! 112: UNREFERENCED_PARAMETER(hWnd); ! 113: #endif ! 114: ! 115: // set up our local entry ! 116: SvrTableSz++; ! 117: strcpy(SvrTable[0].name, szLocal); ! 118: SvrTable[0].iStatus = SS_LOCAL; ! 119: ! 120: // set up remote entries ! 121: #ifdef RPC ! 122: mdlrpc_ProtocolStack.TransportType = RPC_TRANSPORT_NAMEPIPE; ! 123: mdlrpc_ProtocolStack.TransportInfo = "\\device\\namedpipe\\mdlrpc"; ! 124: mdlrpc_ProtocolStack.TransportInfoLength = \ ! 125: strlen(mdlrpc_ProtocolStack.TransportInfo) + 1; ! 126: // add 1 for terminating null ! 127: ! 128: /* Call the Microsoft RPC V1.0 Alpha API function that lets */ ! 129: /* the client establish a connection with the server. */ ! 130: /* NOTE: This API function will be replaced in future */ ! 131: /* releases by the standard DCE RPC function. */ ! 132: status = RpcBindToInterface(&mdlrpc_ProtocolStack, ! 133: 0L, ! 134: &hMandel); ! 135: if (status) { ! 136: sprintf(pszFail, "RpcBindToInterface returned 0x%x\n", status); ! 137: strcat(pszFail, "Please verify that the server side of the Mandel distributed application is running.\n"); ! 138: MessageBox(hWnd, pszFail, "Mandelbrot RPC Server Not Started", ! 139: MB_ICONHAND | MB_SYSTEMMODAL); ! 140: PostMessage(hWnd, WM_DESTROY, 0, 0L); ! 141: return FALSE; ! 142: } ! 143: #endif ! 144: ! 145: // good, we succeeded ! 146: return TRUE; ! 147: } ! 148: ! 149: ! 150: /* ! 151: * CheckDrawStatus -- ! 152: * ! 153: * This function does a check of all buffers being drawn. ! 154: * ! 155: * If it finds an idle pipe, and there is work to be done, it assigns ! 156: * a line, and writes out the request. ! 157: * If it finds a read-pending pipe, it checks if the read has completed. ! 158: * If it has, it is read and a message is sent so the read data can ! 159: * be processed. ! 160: * ! 161: * RETURNS ! 162: * TRUE - we did a piece of work ! 163: * FALSE - we could not find any work to do. ! 164: */ ! 165: ! 166: BOOL CheckDrawStatus( HWND hwnd) ! 167: { ! 168: ! 169: static int iWork = 0; ! 170: int iLast; ! 171: CALCBUF cb; ! 172: PDWORD pbBuf; ! 173: ! 174: // If no pipes, forget it ! 175: if (SvrTableSz == 0) ! 176: return FALSE; ! 177: ! 178: // Move on from where we left off ! 179: ! 180: iLast = iWork; ! 181: ! 182: while ( TRUE ) ! 183: { ! 184: iWork++; ! 185: ! 186: if (iWork == SvrTableSz) ! 187: iWork = 0; ! 188: ! 189: // Check the status ! 190: switch(SvrTable[iWork].iStatus) { ! 191: ! 192: case SS_PAINTING: ! 193: break; ! 194: ! 195: case SS_IDLE: ! 196: // Idle; assign it a piece of work ! 197: if ((long)dwCurrentLine > rclPicture.xRight) ! 198: break; ! 199: ! 200: if (!fRemoteWork) ! 201: break; ! 202: // cb is of type CALCBUF; ! 203: // rectangle, precision, threshold and complex point ! 204: cb.rclDraw.xLeft = dwCurrentLine; ! 205: cb.rclDraw.xRight = dwCurrentLine + iLines - 1; ! 206: cb.rclDraw.yTop = rclPicture.yTop; ! 207: cb.rclDraw.yBottom = rclPicture.yBottom; ! 208: cb.dblPrecision = dPrecision; ! 209: cb.dwThreshold = dwThreshold; ! 210: cb.cptLL = cptLL; ! 211: ! 212: SvrTable[iWork].dwLine = dwCurrentLine; ! 213: dwCurrentLine += iLines; ! 214: SvrTable[iWork].iStatus = SS_READPENDING; ! 215: SvrTable[iWork].cPicture = cPictureID; ! 216: SvrTable[iWork].cLines = iLines; ! 217: ! 218: return TRUE; ! 219: ! 220: case SS_LOCAL: ! 221: // Do a chunk of work locally ! 222: ! 223: if ((long)dwCurrentLine > rclPicture.xRight) { ! 224: if (fContinueZoom == TRUE) { ! 225: if ((fZoomIn == TRUE) && (dPrec < (double)MINPREC)) ! 226: fZoomIn = FALSE; // start zooming out ! 227: if ((fZoomIn == FALSE) && (dPrec > (double)MAXPREC)) ! 228: fZoomIn = TRUE; ! 229: if (fZoomIn) { ! 230: CountHistogram(); ! 231: rcZoom.top = iHistMaxJ * (WIDTH/4); ! 232: rcZoom.bottom = rcZoom.top + (WIDTH/4) - 1; ! 233: rcZoom.left = iHistMaxI * (HEIGHT/4); ! 234: rcZoom.right = rcZoom.left + (HEIGHT/4) - 1; ! 235: fRectDefined = TRUE; ! 236: PostMessage(hwnd, WM_COMMAND, IDM_ZOOMIN, 0L); ! 237: } ! 238: else ! 239: PostMessage(hwnd, WM_COMMAND, IDM_ZOOMOUT, 0L); ! 240: } ! 241: break; ! 242: } ! 243: ! 244: if (!TakeDrawBuffer()) ! 245: break; ! 246: ! 247: pbBuf = GetDrawBuffer(); ! 248: ! 249: cb.rclDraw.xLeft = dwCurrentLine; ! 250: cb.rclDraw.xRight = dwCurrentLine+ iLines-1; ! 251: cb.rclDraw.yTop = rclPicture.yTop; ! 252: cb.rclDraw.yBottom = rclPicture.yBottom; ! 253: ! 254: ! 255: MandelCalc(&cptLL, ! 256: &(cb.rclDraw), ! 257: dPrecision, ! 258: dwThreshold, ! 259: (PLINEBUF)pbBuf); ! 260: ! 261: FreeDrawBuffer(); ! 262: ! 263: SvrTable[iWork].cPicture = cPictureID; ! 264: SvrTable[iWork].dwLine = dwCurrentLine; ! 265: SvrTable[iWork].cLines = iLines; ! 266: ! 267: PostMessage(hwnd, WM_PAINTLINE, ! 268: (UINT)iWork, ! 269: 0L); ! 270: dwCurrentLine += iLines; ! 271: return TRUE; ! 272: ! 273: } ! 274: ! 275: ! 276: // If we made the full loop, we're done ! 277: if (iWork == iLast) ! 278: return FALSE; ! 279: } ! 280: } ! 281: ! 282: ! 283: /* ! 284: * SetNewCalc -- ! 285: * ! 286: * This sets up new information for a drawing and ! 287: * updates the drawing ID so any calculations in progress will not ! 288: * be mixed in. ! 289: */ ! 290: ! 291: void SetNewCalc( CPOINT cptUL, double dPrec, RECT rc) ! 292: { ! 293: ! 294: /* ! 295: * First, the base point. We need to translate from upper left to ! 296: * lower left. ! 297: */ ! 298: ! 299: cptLL.real = cptUL.real; ! 300: cptLL.imag = cptUL.imag - (dPrec * (rc.bottom - rc.top)); ! 301: ! 302: // Now the precision ! 303: dPrecision = dPrec; ! 304: ! 305: // The rectangle. Once again, translate. ! 306: rclPicture.xLeft = (long) rc.left; ! 307: rclPicture.xRight = (long) rc.right; ! 308: rclPicture.yBottom = (long) rc.top; ! 309: rclPicture.yTop = (long) rc.bottom; ! 310: ! 311: // Current line, start of drawing ! 312: dwCurrentLine = rclPicture.xLeft; ! 313: ! 314: dwThreshold = CalcThreshold(dPrecision); ! 315: ! 316: ! 317: } ! 318: ! 319: void IncPictureID(void) ! 320: { ! 321: cPictureID++; ! 322: } ! 323: ! 324: /* ! 325: * CheckDrawing -- ! 326: * ! 327: * Just a sanity check here -- a function to check to make sure that we're ! 328: * on the right drawing ! 329: */ ! 330: ! 331: BOOL ! 332: CheckDrawingID( int id) ! 333: { ! 334: return (id == cPictureID) ? TRUE : FALSE; ! 335: } ! 336: ! 337: ! 338: /* ! 339: * TakeDrawBuffer/ GetDrawBuffer/ FreeDrawBuffer / ReturnDrawBuffer ! 340: * ! 341: * These functions hide a handle to a buffer of memory. ! 342: * ! 343: * TakeDrawBuffer ensures only one pipe read at a time. ! 344: * GetDrawBuffer locks the handle and returns a pointer. ! 345: * FreeDrawBuffer unlocks the handle. ! 346: * ReturnDrawBuffer unlocks the handle and lets another pipe read go. ! 347: */ ! 348: ! 349: static BOOL fBufferTaken = FALSE; ! 350: static HANDLE hSharedBuf = NULL; ! 351: ! 352: ! 353: BOOL ! 354: TakeDrawBuffer( void ) ! 355: { ! 356: ! 357: if (fBufferTaken) ! 358: { ! 359: return FALSE; ! 360: } ! 361: ! 362: if (hSharedBuf == NULL) ! 363: { ! 364: hSharedBuf = LocalAlloc(LMEM_MOVEABLE, MAX_BUFSIZE); ! 365: if (hSharedBuf == NULL) ! 366: return FALSE; ! 367: } ! 368: fBufferTaken = TRUE; ! 369: return TRUE; ! 370: } ! 371: ! 372: ! 373: ! 374: PDWORD ! 375: GetDrawBuffer( void ) ! 376: { ! 377: ! 378: if (hSharedBuf == NULL) ! 379: return NULL; ! 380: ! 381: return (PDWORD) LocalLock(hSharedBuf); ! 382: } ! 383: ! 384: ! 385: ! 386: void ! 387: FreeDrawBuffer( void ) ! 388: { ! 389: LocalUnlock(hSharedBuf); ! 390: } ! 391: ! 392: ! 393: void ! 394: ReturnDrawBuffer( void ) ! 395: { ! 396: fBufferTaken = FALSE; ! 397: } ! 398: ! 399: ! 400: ! 401: /* ! 402: * CalcThreshold -- ! 403: * ! 404: * We need an iteration threshold beyond which we give up. We want it to ! 405: * increase the farther we zoom in. This code generates a threshold value ! 406: * based on the precision of drawing. ! 407: * ! 408: * RETURNS ! 409: * ! 410: * threshold calculated based on precision ! 411: */ ! 412: ! 413: ! 414: DWORD CalcThreshold(double precision) ! 415: { ! 416: DWORD thres = 25; ! 417: double multiplier = (double) 100; ! 418: ! 419: /* for every 100, multiply by 2 */ ! 420: while ( (precision *= multiplier) < (double)1) ! 421: thres *= 2; ! 422: ! 423: return thres; ! 424: } ! 425: ! 426: ! 427: ! 428: /* ! 429: * QueryThreshold -- ! 430: * ! 431: * Callback for finding out what the current drawing's threshold is. ! 432: */ ! 433: ! 434: DWORD QueryThreshold( void ) ! 435: { ! 436: return dwThreshold; ! 437: } ! 438: ! 439: ! 440: /* ! 441: * ! 442: * GetServerCount -- ! 443: * ! 444: * Returns the number of servers in the table. ! 445: */ ! 446: ! 447: int ! 448: GetServerCount( void ) ! 449: { ! 450: return (int) SvrTableSz-1; ! 451: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.