|
|
1.1 root 1: /******************************************************************************\
2: * This is a part of the Microsoft Source Code Samples.
3: * Copyright (C) 1993 Microsoft Corporation.
4: * All rights reserved.
5: * This source code is only intended as a supplement to
6: * Microsoft Development Tools and/or WinHelp documentation.
7: * See these sources for detailed information regarding the
8: * Microsoft samples programs.
9: \******************************************************************************/
10:
11: /*************************************************************************\
12: * PROGRAM: server32.c
13: *
14: * PURPOSE:
15: *
16: * To demonstrate the use of named pipes and the overlapped structure.
17: * This code serves as the server side of the named pipe instances.
18: * For more details on an overview of this codes designs or use, see
19: * the README file. For details on the implementation, see the comments
20: * in this code.
21: *
22: *
23: \*************************************************************************/
24:
25: #define STRICT
26: #include <windows.h>
27: #include "server32.h"
28:
29: #include <string.h>
30: #include <stdio.h>
31: #include <stdlib.h>
32:
33: // clients[] is a global array of
34: // structures used to keep track
35: // of the multiple instances of
36: // the server side of the named
37: // pipe. As a client connects
38: // to a given instance, a new
39: // server thread is created and
40: // added to the array.
41: WRTHANDLE clients[MAX_PIPE_INSTANCES];
42: DWORD clientCount = 0; // Global count of connected clients.
43:
44: HWND hWnd;
45: HANDLE hInst;
46:
47:
48: /*************************************************************************\
49: *
50: * FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
51: *
52: * PURPOSE: calls initialization function, processes message loop
53: *
54: * COMMENTS:
55: *
56: \*************************************************************************/
57:
58: int APIENTRY WinMain (HINSTANCE hInstance,
59: HINSTANCE hPrevInstance,
60: LPSTR lpCmdLine,
61: int nCmdShow)
62:
63:
64: {
65:
66: MSG msg;
67: WNDCLASS wc;
68:
69:
70: UNREFERENCED_PARAMETER( lpCmdLine );
71: UNREFERENCED_PARAMETER( hPrevInstance );
72:
73: hInst = hInstance;
74:
75: wc.style = 0;
76: wc.lpfnWndProc = (WNDPROC)MainWndProc;
77: wc.cbClsExtra = 0;
78: wc.cbWndExtra = 0;
79: wc.hInstance = hInstance;
80: wc.hIcon = LoadIcon (hInstance, "npserver");
81: wc.hCursor = LoadCursor (NULL, IDC_ARROW);
82: wc.hbrBackground = GetStockObject (WHITE_BRUSH);
83: wc.lpszMenuName = "PipeMenu";
84: wc.lpszClassName = "PipeWClass";
85:
86: RegisterClass(&wc);
87:
88: hWnd = CreateWindow ("PipeWClass",
89: "Server32 Named Pipe Sample",
90: WS_OVERLAPPEDWINDOW,
91: CW_USEDEFAULT,
92: CW_USEDEFAULT,
93: CW_USEDEFAULT,
94: CW_USEDEFAULT,
95: NULL,
96: NULL,
97: hInstance,
98: NULL);
99:
100:
101: ShowWindow (hWnd, nCmdShow);
102:
103: while (GetMessage (&msg, NULL, 0, 0))
104: DispatchMessage (&msg);
105:
106: return (msg.wParam);
107:
108: }
109:
110: /*************************************************************************\
111: *
112: * FUNCTION: MainWndProc (HWND, UINT, WPARAM, LPARAM)
113: *
114: * PURPOSE: To process messages. To launch client and server threads
115: *
116: \*************************************************************************/
117:
118: LONG CALLBACK MainWndProc (HWND hwnd,
119: UINT message,
120: WPARAM wParam,
121: LPARAM lParam)
122: {
123:
124: LONG lpServerThreadID;
125: PAINTSTRUCT paintStruct;
126: HDC hDC;
127:
128: switch (message)
129: {
130: case WM_PAINT:
131: // DrawBranch is used to paint the spools and text to the window.
132: hDC = BeginPaint (hwnd, &paintStruct);
133: DrawBranch (hDC);
134: EndPaint (hwnd, &paintStruct);
135: return(0);
136:
137: case WM_CREATE :
138: // Create the first instance of a server side of the pipe.
139: CreateThread ((LPSECURITY_ATTRIBUTES)NULL, // No security.
140: (DWORD)0, // Same stack size.
141: (LPTHREAD_START_ROUTINE)ServerProc,// Thread procedure.
142: (LPVOID)&hwnd, // Parameter.
143: (DWORD)0, // Start immediatly.
144: (LPDWORD)&lpServerThreadID); // Thread ID.
145: return (0);
146:
147: case WM_DESTROY :
148: PostQuitMessage (0);
149: return (0);
150: }
151: return DefWindowProc (hwnd, message, wParam, lParam);
152: }
153:
154:
155:
156: /*************************************************************************\
157: *
158: * PROCEDURE: ServerProc (HWND *hWnd)
159: *
160: * PURPOSE:
161: *
162: * A thread procedure, which creates an instance of the server side of
163: * the named pipe, and then blocks waiting for a client to connect.
164: * Once the client connects, a global array is updated with the specific
165: * clients information, and this procedure is called again
166: * to launch another waiting server thread. After launching the new
167: * thread, this thread begins to loop, reading the named pipe. When
168: * a message comes from it's client, it uses TellAll() to broadcast
169: * the message to the other clients in the array.
170: *
171: * CALLED BY:
172: *
173: * ServerProc();
174: * WinMain();
175: *
176: * CALLS TO:
177: *
178: * TellAll();
179: * ServerProc().
180: *
181: * COMMENTS:
182: *
183: * Clients is a global array which hold information on each client
184: * connected to the named pipe. This procedure recieves a buffer.
185: * It then steps through this global array, and for each client it
186: * writes the buffer.
187: *
188: \*************************************************************************/
189:
190: VOID ServerProc(HWND *hWnd)
191: {
192: HANDLE hPipe; // Pipe handle.
193: CHAR inBuf[IN_BUF_SIZE] = ""; // Input buffer for pipe.
194: DWORD ServerThreadID; // Used for CreateThread().
195:
196: CHAR errorBuf[LINE_LEN] = ""; // Used for error messages.
197: DWORD bytesRead; // Used in ReadFile().
198: DWORD retCode; // Used to trap return codes.
199: DWORD clientIndex; // Index into global array, for this
200: // instances client.
201: DWORD lastError; // Traps returns from GetLastError().
202: BOOL ExitLoop = FALSE; // Boolean Flag to exit loop.
203:
204: OVERLAPPED OverLapWrt; // Overlapped structure for writing.
205: HANDLE hEventWrt; // Event handle for overlapped write.
206:
207: OVERLAPPED OverLapRd; // Overlapped structure for reading.
208: HANDLE hEventRd; // Event handle for overlapped reads.
209: DWORD bytesTransRd; // Bytes transferred by overlapped.
210: PSECURITY_DESCRIPTOR pSD;
211: SECURITY_ATTRIBUTES sa;
212:
213: // create a security NULL security
214: // descriptor, one that allows anyone
215: // to write to the pipe... WARNING
216: // entering NULL as the last attribute
217: // of the CreateNamedPipe() will
218: // indicate that you wish all
219: // clients connecting to it to have
220: // all of the same security attributes
221: // as the user that started the
222: // pipe server.
223:
224: pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
225: SECURITY_DESCRIPTOR_MIN_LENGTH);
226:
227: if (pSD == NULL)
228: {
229: MessageBox (*hWnd, "Error in LocalAlloc for pSD",
230: "Debug: ServerProc()", MB_OK);
231: return;
232: }
233:
234: if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
235: {
236: wsprintf (errorBuf, "Error: InitializeSecurityDescriptor() %d",
237: GetLastError());
238: MessageBox (*hWnd, errorBuf, "Debug: ServerProc()", MB_OK);
239: LocalFree((HLOCAL)pSD);
240: return;
241: }
242:
243: // add a NULL disc. ACL to the
244: // security descriptor.
245:
246: if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE))
247: {
248: wsprintf (errorBuf, "Error: SetSecurityDescriptorDacl() %d",
249: GetLastError());
250: MessageBox (*hWnd, errorBuf, "Debug: ServerProc()", MB_OK);
251: LocalFree((HLOCAL)pSD);
252: return;
253: }
254:
255: sa.nLength = sizeof(sa);
256: sa.lpSecurityDescriptor = pSD;
257: sa.bInheritHandle = TRUE;
258:
259: // Create a local named pipe with
260: // the name '\\.\PIPE\test'. The
261: // '.' signifies local pipe.
262: hPipe = CreateNamedPipe ("\\\\.\\PIPE\\test", // Pipe name = 'test'.
263: PIPE_ACCESS_DUPLEX // 2 way pipe.
264: | FILE_FLAG_OVERLAPPED, // Use overlapped structure.
265: PIPE_WAIT // Wait on messages.
266: | PIPE_READMODE_MESSAGE // Specify message mode pipe.
267: | PIPE_TYPE_MESSAGE,
268: MAX_PIPE_INSTANCES, // Maximum instance limit.
269: OUT_BUF_SIZE, // Buffer sizes.
270: IN_BUF_SIZE,
271: TIME_OUT, // Specify time out.
272: &sa); // Security attributes.
273:
274: // Check Errors.
275: if ((DWORD)hPipe == 0xFFFFFFFF)
276: {
277:
278: retCode = GetLastError(); // Report any error, it should always
279: wsprintf (errorBuf, // succeed.
280: "Error return code from CreateNamedPipe = %li.",
281: retCode);
282: MessageBox (*hWnd, errorBuf, "Debug Window",
283: MB_ICONINFORMATION | MB_OK | MB_APPLMODAL);
284: };
285:
286: // Block until a client connects.
287: ConnectNamedPipe(hPipe, NULL);
288:
289: // Create and init overlap for writing.
290: hEventWrt = CreateEvent (NULL, TRUE, FALSE, NULL);
291: memset (&OverLapWrt, 0, sizeof(OVERLAPPED));
292: OverLapWrt.hEvent = hEventWrt;
293:
294: // Set the clientIndex, then increment
295: // the count. Fill in the structure
296: // for this client in the array.
297: clientIndex = clientCount++;
298: clients[clientIndex].hPipe = hPipe;
299: clients[clientIndex].live = TRUE;
300: clients[clientIndex].overLap = OverLapWrt;
301: clients[clientIndex].hEvent = hEventWrt;
302:
303: // Create and init overlap for reading.
304: hEventRd = CreateEvent(NULL,TRUE,FALSE,NULL);
305: memset (&OverLapRd, 0, sizeof(OVERLAPPED));
306: OverLapRd.hEvent = hEventRd;
307:
308: // Read from the client, the first
309: // first message should always be
310: // the clients user name.
311: retCode = ReadFile (hPipe, inBuf, PLEASE_READ, &bytesRead, &OverLapRd);
312:
313: if (!retCode)
314: lastError = GetLastError();
315:
316: if (lastError == ERROR_IO_PENDING) // Wait on read if need be.
317: WaitForSingleObject (hEventRd, (DWORD)-1);
318:
319: // Put client's name in the array.
320: strcpy (clients[clientIndex].Name, inBuf);
321:
322: // Create a thread which will make
323: // another server instance of the
324: // named pipe.
325: CreateThread ((LPSECURITY_ATTRIBUTES)NULL, // No security attributes.
326: (DWORD)0, // Use same stack size.
327: (LPTHREAD_START_ROUTINE)ServerProc, // Thread procedure.
328: (LPVOID)hWnd, // Parameter to pass.
329: (DWORD)0, // Run immediately.
330: (LPDWORD)&ServerThreadID); // Thread identifier.
331:
332: TellAll(""); // Forces a paint, draws a red spool
333: // and name for this client.
334:
335: // Do loop which basically reads from
336: // this specific client, and then
337: // uses TellAll() to broadcast the
338: // message to all the connected
339: // clients.
340: do{
341: // Read the pipe.
342: retCode = ReadFile (hPipe, inBuf, PLEASE_READ, &bytesRead, &OverLapRd);
343:
344: // Check for three kinds of errors:
345: // If Error = IO_PENDING, wait til
346: // the event handle signals success,
347: // If BROKEN_PIPE, exit the do loop.
348: // Any other error, flag it to the
349: // user and exit the do loop.
350: if (!retCode)
351: {
352: lastError = GetLastError();
353:
354: switch (lastError)
355: {
356: // IO_PENDING, wait on the event.
357: case ERROR_IO_PENDING:
358: WaitForSingleObject (hEventRd, (DWORD)-1);
359: break;
360: // Pipe is broken, exit the loop.
361: case ERROR_BROKEN_PIPE:
362: ExitLoop = TRUE;
363: break;
364: // Something else is wrong, exit the
365: // the loop after telling the user.
366: default:
367: wsprintf (errorBuf, "ReadFile Error in ServerProc()= %d",
368: lastError);
369: MessageBox (*hWnd, errorBuf, "Debug Information", MB_OK);
370: ExitLoop = TRUE;
371: break;
372: }
373: }
374:
375: if (!ExitLoop)
376: {
377: GetOverlappedResult (hPipe, &OverLapRd, &bytesTransRd, FALSE);
378:
379: // Use TellAll to broadcast the message.
380: if (bytesTransRd)
381: TellAll(inBuf);
382: else
383: TellAll("");
384: }
385:
386: }while(!ExitLoop);
387:
388: clients[clientIndex].live = FALSE; // Turns spool gray.
389: CloseHandle (hPipe); // Close handles.
390: CloseHandle (hEventRd);
391: CloseHandle (hEventWrt);
392: DisconnectNamedPipe (hPipe); // Close pipe instance.
393: ExitThread(0); // Clean up and die.
394: }
395:
396:
397: /*************************************************************************\
398: *
399: * PROCEDURE: TellAll (CHAR *buffer)
400: *
401: * PURPOSE:
402: *
403: * To write the buffer (input parameter) to all of the clients listed
404: * in the global array "clients".
405: *
406: * CALLED BY:
407: *
408: * ServerProc();
409: *
410: * COMMENTS:
411: *
412: * Clients is a global array which hold information on each client
413: * connected to the named pipe. This procedure recieves a buffer.
414: * It then steps through this global array, and for each client it
415: * writes the buffer.
416: *
417: \*************************************************************************/
418:
419: VOID TellAll( CHAR *buffer )
420: {
421: DWORD i; // Index through array.
422: DWORD bytesWritten; // Used in WriteFile().
423: DWORD retCode; // Traps return codes.
424: CHAR Buf[LINE_LEN]; // Message Buffer.
425: DWORD lastError; // Traps returns from GetLastError().
426:
427: for(i=0; i < clientCount; i++) // For all clients in the array.
428: {
429: // If client isn't alive, don't waste
430: // time writing to it.
431: if (clients[i].live)
432: {
433: retCode = WriteFile (clients[i].hPipe, buffer, strlen(buffer),
434: &bytesWritten, &clients[i].overLap);
435:
436: // Check 3 kinds of errors: IO_PENDING,
437: // NO_DATA, or other. Wait on event
438: // handle if IO_PENDING, else, if it's
439: // anything other than NO_DATA (pipe
440: // client disconnected), flag the user.
441: // In any case, if it's not IO_PENDING,
442: // clients[i].live = FALSE, spool turns
443: // gray.
444: if (!retCode)
445: {
446: lastError = GetLastError();
447:
448: // IO_PENDING, wait on event handle.
449: if (lastError == ERROR_IO_PENDING)
450: {
451: WaitForSingleObject (clients[i].hEvent, (DWORD)-1);
452: }
453: else
454: {
455: // If not NO_DATA, flag user.
456: if (lastError != ERROR_NO_DATA)
457: {
458: wsprintf (Buf, "%s = %d", buffer, GetLastError());
459: MessageBox(hWnd, Buf, "Debug,TellAll:", MB_OK);
460: }
461: clients[i].live = FALSE;
462: }
463: }
464: } //if client.live
465: } // for loop
466: // Paint window with new information.
467: InvalidateRect(hWnd, NULL, TRUE);
468: }
469:
470:
471:
472: /*************************************************************************\
473: *
474: * PROCEDURE: DrawBranch (HDC hDC)
475: *
476: * PURPOSE:
477: *
478: * To draw one of four bitmaps for each client, depending upon the clients
479: * status (alive = red spool, dead or disconnected = gray), and location in
480: * the array. It also draws the clients user name beside the spool.
481: * This procedure is executed when the WM_PAINT message is trapped.
482: *
483: * CALLED BY:
484: *
485: * WinMain();
486: *
487: * COMMENTS:
488: *
489: \*************************************************************************/
490: VOID DrawBranch(HDC hDC)
491: {
492: // Spool bitmaps.
493: HBITMAP hEndLive, hEndDead, hMidLive, hMidDead, hBitMap;
494:
495: HDC hDCMem;
496: int X, Y;
497: BITMAP bm;
498: POINT ptSize, ptOrg;
499: DWORD index;
500:
501: // Load bitmaps: two red (live),
502: // two dead (gray). End = end
503: // of tree (last client to connect),
504: // mid means in the middle somewhere.
505: hEndLive = LoadBitmap (hInst, "EndLive");
506: hEndDead = LoadBitmap (hInst, "EndDead");
507:
508: hMidLive = LoadBitmap (hInst, "MidLive");
509: hMidDead = LoadBitmap (hInst, "MidDead");
510:
511: // For each client, determine if
512: // if alive or not, and position;
513: // then blt appropriate map and
514: // clients name.
515: for (index = 0; index < clientCount; index++)
516: {
517:
518: if (index < clientCount - 1) // ClientCount - 1 = last (end) client.
519: {
520: if(clients[index].live) // If live = red, else = gray.
521: hBitMap = hMidLive;
522: else
523: hBitMap = hMidDead;
524: }
525: else
526: {
527: if(clients[index].live) // If live = red, else = gray.
528: hBitMap = hEndLive;
529: else
530: hBitMap = hEndDead;
531: }
532: // Calculate coordinates:
533: X = BITMAP_X; // X position is constant.
534: Y = index * BITMAP_Y; // Y is based on index in the array.
535:
536: // Blt the chosen map.
537: hDCMem = CreateCompatibleDC(hDC);
538: SelectObject(hDCMem, hBitMap);
539: SetMapMode(hDCMem, GetMapMode(hDC));
540:
541: GetObject(hBitMap, sizeof(BITMAP), &bm);
542:
543: ptSize.x = bm.bmWidth;
544: ptSize.y = bm.bmHeight;
545: DPtoLP (hDC, &ptSize, 1);
546:
547: ptOrg.x = 0;
548: ptOrg.y = 0;
549: DPtoLP (hDCMem, &ptOrg, 1);
550:
551: BitBlt(hDC, X, Y, ptSize.x, ptSize.y,
552: hDCMem, ptOrg.x, ptOrg.y, SRCCOPY);
553:
554:
555: X = NAME_X; // Relocate X,Y for clients name.
556: Y += NAME_Y;
557: // Write name next to spool.
558: TextOut (hDC, X, Y, clients[index].Name, strlen(clients[index].Name));
559: DeleteDC(hDCMem);
560: }
561:
562:
563: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.