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