|
|
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: *
1.1.1.2 ! root 7: * Copyright (C) 1990, 1992 Microsoft Corporation.
1.1 root 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
1.1.1.2 ! root 11: * to lower-left is (0,0) before we ship it out onto
1.1 root 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: #include "mandel.h"
1.1.1.2 ! root 44:
1.1 root 45: /*
1.1.1.2 ! root 46: * Tuning parameters
1.1 root 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: {
1.1.1.2 ! root 111: #ifdef RPC
! 112: RPC_STATUS status; // returned by RPC API function
! 113: unsigned char * pszUuid = "12345678-1234-1234-1234-123456789ABC";
! 114: unsigned char * pszProtocolSequence = "ncacn_np";
! 115: unsigned char * pszNetworkAddress = NULL;
! 116: unsigned char * pszEndpoint = "\\pipe\\mandel";
! 117: unsigned char * pszOptions = NULL;
! 118: unsigned char * pszStringBinding; // long string
! 119: #endif
! 120:
1.1 root 121: #ifndef RPC
122: UNREFERENCED_PARAMETER(hWnd);
123: #endif
124:
125: // set up our local entry
126: SvrTableSz++;
127: strcpy(SvrTable[0].name, szLocal);
128: SvrTable[0].iStatus = SS_LOCAL;
129:
130: #ifdef RPC
1.1.1.2 ! root 131: /* Select named pipes as the transport type and provide the */
! 132: /* path to the server and named pipe that is used for RPC. */
! 133:
! 134: /* Call the Microsoft RPC V1.0 Beta API function that lets */
! 135: /* the client establish a connection with the server. */
! 136:
! 137: status = RpcStringBindingCompose(pszUuid,
! 138: pszProtocolSequence,
! 139: pszNetworkAddress,
! 140: pszEndpoint,
! 141: pszOptions,
! 142: &pszStringBinding);
! 143: sprintf(pszFail, "RpcStringBindingCompose returned 0x%x for %s\n",
! 144: status, pszStringBinding);
! 145: MessageBox(hWnd, pszFail, "Mandelbrot RPC Application",
! 146: MB_ICONINFORMATION | MB_SYSTEMMODAL);
1.1 root 147: if (status) {
1.1.1.2 ! root 148: PostMessage(hWnd, WM_DESTROY, 0, 0L);
! 149: return FALSE;
! 150: }
! 151:
! 152: status = RpcBindingFromStringBinding(pszStringBinding,
! 153: &hMandel);
! 154:
! 155: sprintf(pszFail, "RpcBindingFromStringBinding returned 0x%x for %s\n",\
! 156: status, pszStringBinding);
! 157: MessageBox(hWnd, pszFail, "Mandelbrot RPC Application",
! 158: MB_ICONINFORMATION | MB_SYSTEMMODAL);
! 159: if (status) {
! 160: PostMessage(hWnd, WM_DESTROY, 0, 0L);
! 161: return FALSE;
1.1 root 162: }
163: #endif
164:
165: // good, we succeeded
166: return TRUE;
167: }
168:
169:
170: /*
171: * CheckDrawStatus --
172: *
173: * This function does a check of all buffers being drawn.
174: *
175: * If it finds an idle pipe, and there is work to be done, it assigns
176: * a line, and writes out the request.
177: * If it finds a read-pending pipe, it checks if the read has completed.
178: * If it has, it is read and a message is sent so the read data can
179: * be processed.
180: *
181: * RETURNS
182: * TRUE - we did a piece of work
183: * FALSE - we could not find any work to do.
184: */
185:
186: BOOL CheckDrawStatus( HWND hwnd)
187: {
188:
189: static int iWork = 0;
190: int iLast;
191: CALCBUF cb;
192: PDWORD pbBuf;
193:
194: // If no pipes, forget it
195: if (SvrTableSz == 0)
196: return FALSE;
197:
198: // Move on from where we left off
199:
200: iLast = iWork;
201:
202: while ( TRUE )
203: {
204: iWork++;
205:
206: if (iWork == SvrTableSz)
207: iWork = 0;
208:
209: // Check the status
210: switch(SvrTable[iWork].iStatus) {
211:
212: case SS_PAINTING:
213: break;
214:
215: case SS_IDLE:
216: // Idle; assign it a piece of work
217: if ((long)dwCurrentLine > rclPicture.xRight)
218: break;
219:
220: if (!fRemoteWork)
221: break;
222: // cb is of type CALCBUF;
223: // rectangle, precision, threshold and complex point
224: cb.rclDraw.xLeft = dwCurrentLine;
225: cb.rclDraw.xRight = dwCurrentLine + iLines - 1;
226: cb.rclDraw.yTop = rclPicture.yTop;
227: cb.rclDraw.yBottom = rclPicture.yBottom;
228: cb.dblPrecision = dPrecision;
229: cb.dwThreshold = dwThreshold;
230: cb.cptLL = cptLL;
231:
232: SvrTable[iWork].dwLine = dwCurrentLine;
233: dwCurrentLine += iLines;
234: SvrTable[iWork].iStatus = SS_READPENDING;
235: SvrTable[iWork].cPicture = cPictureID;
236: SvrTable[iWork].cLines = iLines;
237:
238: return TRUE;
239:
240: case SS_LOCAL:
241: // Do a chunk of work locally
242:
243: if ((long)dwCurrentLine > rclPicture.xRight) {
244: if (fContinueZoom == TRUE) {
245: if ((fZoomIn == TRUE) && (dPrec < (double)MINPREC))
246: fZoomIn = FALSE; // start zooming out
247: if ((fZoomIn == FALSE) && (dPrec > (double)MAXPREC))
248: fZoomIn = TRUE;
249: if (fZoomIn) {
250: CountHistogram();
251: rcZoom.top = iHistMaxJ * (WIDTH/4);
252: rcZoom.bottom = rcZoom.top + (WIDTH/4) - 1;
253: rcZoom.left = iHistMaxI * (HEIGHT/4);
254: rcZoom.right = rcZoom.left + (HEIGHT/4) - 1;
255: fRectDefined = TRUE;
256: PostMessage(hwnd, WM_COMMAND, IDM_ZOOMIN, 0L);
257: }
258: else
259: PostMessage(hwnd, WM_COMMAND, IDM_ZOOMOUT, 0L);
260: }
261: break;
262: }
263:
264: if (!TakeDrawBuffer())
265: break;
266:
267: pbBuf = GetDrawBuffer();
268:
269: cb.rclDraw.xLeft = dwCurrentLine;
270: cb.rclDraw.xRight = dwCurrentLine+ iLines-1;
271: cb.rclDraw.yTop = rclPicture.yTop;
272: cb.rclDraw.yBottom = rclPicture.yBottom;
273:
274:
275: MandelCalc(&cptLL,
276: &(cb.rclDraw),
277: dPrecision,
278: dwThreshold,
279: (PLINEBUF)pbBuf);
280:
281: FreeDrawBuffer();
282:
283: SvrTable[iWork].cPicture = cPictureID;
284: SvrTable[iWork].dwLine = dwCurrentLine;
285: SvrTable[iWork].cLines = iLines;
286:
287: PostMessage(hwnd, WM_PAINTLINE,
288: (UINT)iWork,
289: 0L);
290: dwCurrentLine += iLines;
291: return TRUE;
292:
293: }
294:
295:
296: // If we made the full loop, we're done
297: if (iWork == iLast)
298: return FALSE;
299: }
300: }
301:
302:
303: /*
304: * SetNewCalc --
305: *
306: * This sets up new information for a drawing and
307: * updates the drawing ID so any calculations in progress will not
308: * be mixed in.
309: */
310:
311: void SetNewCalc( CPOINT cptUL, double dPrec, RECT rc)
312: {
313:
314: /*
315: * First, the base point. We need to translate from upper left to
316: * lower left.
317: */
318:
319: cptLL.real = cptUL.real;
320: cptLL.imag = cptUL.imag - (dPrec * (rc.bottom - rc.top));
321:
322: // Now the precision
323: dPrecision = dPrec;
324:
325: // The rectangle. Once again, translate.
326: rclPicture.xLeft = (long) rc.left;
327: rclPicture.xRight = (long) rc.right;
328: rclPicture.yBottom = (long) rc.top;
329: rclPicture.yTop = (long) rc.bottom;
330:
331: // Current line, start of drawing
332: dwCurrentLine = rclPicture.xLeft;
333:
334: dwThreshold = CalcThreshold(dPrecision);
335:
336:
337: }
338:
339: void IncPictureID(void)
340: {
341: cPictureID++;
342: }
343:
344: /*
345: * CheckDrawing --
346: *
347: * Just a sanity check here -- a function to check to make sure that we're
348: * on the right drawing
349: */
350:
351: BOOL
352: CheckDrawingID( int id)
353: {
354: return (id == cPictureID) ? TRUE : FALSE;
355: }
356:
357:
358: /*
359: * TakeDrawBuffer/ GetDrawBuffer/ FreeDrawBuffer / ReturnDrawBuffer
360: *
361: * These functions hide a handle to a buffer of memory.
362: *
363: * TakeDrawBuffer ensures only one pipe read at a time.
364: * GetDrawBuffer locks the handle and returns a pointer.
365: * FreeDrawBuffer unlocks the handle.
366: * ReturnDrawBuffer unlocks the handle and lets another pipe read go.
367: */
368:
369: static BOOL fBufferTaken = FALSE;
370: static HANDLE hSharedBuf = NULL;
371:
372:
373: BOOL
374: TakeDrawBuffer( void )
375: {
376:
377: if (fBufferTaken)
378: {
379: return FALSE;
380: }
381:
382: if (hSharedBuf == NULL)
383: {
1.1.1.2 ! root 384: hSharedBuf = GlobalAlloc(GMEM_MOVEABLE, MAX_BUFSIZE);
1.1 root 385: if (hSharedBuf == NULL)
386: return FALSE;
387: }
388: fBufferTaken = TRUE;
389: return TRUE;
390: }
391:
392:
393:
394: PDWORD
395: GetDrawBuffer( void )
396: {
397:
398: if (hSharedBuf == NULL)
399: return NULL;
400:
1.1.1.2 ! root 401: return (PDWORD) GlobalLock(hSharedBuf);
1.1 root 402: }
403:
404:
405:
406: void
407: FreeDrawBuffer( void )
408: {
1.1.1.2 ! root 409: GlobalUnlock(hSharedBuf);
1.1 root 410: }
411:
412:
413: void
414: ReturnDrawBuffer( void )
415: {
416: fBufferTaken = FALSE;
417: }
418:
419:
420:
421: /*
422: * CalcThreshold --
423: *
424: * We need an iteration threshold beyond which we give up. We want it to
425: * increase the farther we zoom in. This code generates a threshold value
426: * based on the precision of drawing.
427: *
428: * RETURNS
429: *
430: * threshold calculated based on precision
431: */
432:
433:
434: DWORD CalcThreshold(double precision)
435: {
436: DWORD thres = 25;
1.1.1.2 ! root 437: double multiplier = (double) 100.0;
1.1 root 438:
439: /* for every 100, multiply by 2 */
1.1.1.2 ! root 440: while ( (precision *= multiplier) < (double)1.0)
1.1 root 441: thres *= 2;
442:
443: return thres;
444: }
445:
446:
447:
448: /*
449: * QueryThreshold --
450: *
451: * Callback for finding out what the current drawing's threshold is.
452: */
453:
454: DWORD QueryThreshold( void )
455: {
456: return dwThreshold;
457: }
458:
459:
460: /*
461: *
462: * GetServerCount --
463: *
464: * Returns the number of servers in the table.
465: */
466:
467: int
468: GetServerCount( void )
469: {
470: return (int) SvrTableSz-1;
471: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.