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