|
|
1.1 root 1:
2: /******************************************************************************\
3: * This is a part of the Microsoft Source Code Samples.
4: * Copyright (C) 1993 Microsoft Corporation.
5: * All rights reserved.
6: * This source code is only intended as a supplement to
7: * Microsoft Development Tools and/or WinHelp documentation.
8: * See these sources for detailed information regarding the
9: * Microsoft samples programs.
10: \******************************************************************************/
11:
12: /*************************************************************************\
13: * PROGRAM: client32.c
14: *
15: * PURPOSE:
16: *
17: * To demonstrate the use of named pipes and the overlapped structure.
18: * This code serves as the client side of the named pipe instances.
19: * For more details on an overview of this codes designs or use, see
20: * the README file. For details on the implementation, see the comments
21: * in this code.
22: *
23: *
24: \*************************************************************************/
25:
26: #define STRICT
27: #include <windows.h>
28: #include "client32.h"
29:
30: #include <string.h>
31: #include <stdio.h>
32: #include <stdlib.h>
33:
34: HANDLE hInst;
35: HWND hWndClient;
36:
37: CHAR ShrName[LINE_LEN]; // Global: net share name.
38: CHAR ClntName[NAME_SIZE]; // Global: user or pipe client name.
39:
40: /*************************************************************************\
41: *
42: * FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
43: *
44: * PURPOSE: Launches the Client's dialog box.
45: *
46: * COMMENTS:
47: *
48: \*************************************************************************/
49:
50: int APIENTRY WinMain (HINSTANCE hInstance,
51: HINSTANCE hPrevInstance,
52: LPSTR lpCmdLine,
53: int nCmdShow)
54:
55:
56: {
57: DWORD retCode;
58:
59: UNREFERENCED_PARAMETER( nCmdShow );
60: UNREFERENCED_PARAMETER( lpCmdLine );
61: UNREFERENCED_PARAMETER( hPrevInstance );
62:
63: hInst = hInstance;
64: retCode = DialogBox ((HANDLE)hInst, (LPCTSTR)"ClientDialog",
65: NULL, (DLGPROC)ClientDlgProc);
66: return (retCode);
67:
68: }
69:
70:
71: /*************************************************************************\
72: *
73: * PROCEDURE: InitDlgProc (HWND hDlg, WORD wMsg, LONG wParam, LONG lParam)
74: *
75: * PURPOSE: This dialog box prompts the user for a net share name and
76: * a client or user name. These values are placed into global
77: * strings ShrName and ClntName.
78: *
79: * CALLED BY:
80: *
81: * ClientDlgProc();
82: *
83: \*************************************************************************/
84:
85: LONG CALLBACK InitDlgProc (HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
86: {
87:
88: UNREFERENCED_PARAMETER(lParam);
89:
90: switch (wMsg)
91: {
92: case WM_INITDIALOG:
93: PostMessage (GetDlgItem (hDlg, IDD_SVREDIT),
94: EM_LIMITTEXT, LINE_LEN, 0);
95:
96: PostMessage (GetDlgItem (hDlg, IDD_CLNTEDIT),
97: EM_LIMITTEXT, NAME_SIZE, 0);
98: case WM_COMMAND:
99: switch (LOWORD(wParam))
100: { // When the user clicks okay, get the
101: case IDB_INITOK: // share name and user name from the
102: // edit fields.
103: GetWindowText (GetDlgItem (hDlg, IDD_SVREDIT), ShrName, LINE_LEN);
104: GetWindowText (GetDlgItem (hDlg, IDD_CLNTEDIT), ClntName, NAME_SIZE);
105: EndDialog(hDlg, 0);
106: return (0);
107:
108: default:
109: return (0);
110: }
111: default:
112: return (0);
113: }
114: return (0);
115: }
116:
117:
118: /*************************************************************************\
119: *
120: * PROCEDURE: ClientDlgProc (HWND hDlg, WORD wMsg, LONG wParam, LONG lParam)
121: *
122: * PURPOSE: This procedure services the dialog box that serves as an interface
123: * to the named pipe server instance. The larger edit field is used
124: * to read messages from the server instance. The smaller edit field
125: * is used to type messages to the server instance. This procedure
126: * is responsible for connecting to the named pipe, creating a
127: * seperate thread to read the pipe, and sending to the pipe.
128: *
129: * CALLED BY:
130: *
131: * WinMain();
132: *
133: * CALLS TO:
134: *
135: * InitDlgProc();
136: * ReadPipe();
137: *
138: \**************************************************************************/
139:
140: LONG CALLBACK ClientDlgProc (HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
141: {
142: DWORD retCode; // Return code.
143: CHAR errorBuf[LINE_LEN] = ""; // Error message buffer.
144: CHAR outBuf[OUT_BUF_SIZE] = ""; // Buffer trapping message to send.
145: CHAR sendBuf[OUT_BUF_SIZE] = ""; // Buffer used to modify message.
146: DWORD bytesWritten; // Used for WriteFile().
147: DWORD threadID; // Used for CreateThread().
148: CHAR fileName[LINE_LEN+NAME_SIZE+2]; // Used to modify pipe/file name.
149: DWORD lastError; // Used to get returns from GetLastError.
150:
151: static HANDLE hPipe; // File or Pipe handle.
152: static OVERLAPPED OverLapWrt; // Overlapped structure
153: static HANDLE hEventWrt; // Event handle for overlapped writes.
154:
155: UNREFERENCED_PARAMETER( lParam );
156:
157: hWndClient = hDlg;
158:
159: switch (wMsg)
160: {
161:
162: case WM_COMMAND:
163: switch (LOWORD(wParam))
164: {
165:
166: // When the user presses Send: capture the string from the edit
167: // field, prepend it with the user name, and overlap write it to
168: // the server instance of the named pipe.
169:
170: case IDB_SEND: // Get the text from the edit field.
171: GetWindowText (GetDlgItem(hDlg,IDD_EDITWRITE),
172: outBuf, PLEASE_WRITE);
173:
174: // Prepend it with the user name, and
175: // terminate it with a new line
176: // character.
177:
178: wsprintf (sendBuf, "%s%s %s\n", ClntName, ":", outBuf);
179:
180: // Do the overlapped write.
181: retCode = WriteFile (hPipe, sendBuf, PLEASE_WRITE,
182: &bytesWritten, &OverLapWrt);
183: if (!retCode)
184: {
185: lastError = GetLastError();
186: // If Error = IO_PENDING, wait til
187: // the event signals success.
188: if (lastError == ERROR_IO_PENDING)
189: WaitForSingleObject (hEventWrt, (DWORD)-1);
190: }
191:
192: return (0);
193:
194: default:
195: return (0);
196:
197: }
198:
199:
200: case WM_INITCLIENT:
201:
202: // On initialization, use the Init dialog box prompt the user for a
203: // net share name and a client or user name. A share name of "."
204: // means that the named pipe is local to this machine. Named pipe
205: // names should have the form '\\.\PIPE\<pipename>', for a local machine
206: // or '\\<machinename>\PIPE\<pipename>' for remote machines.
207: // Once the share name is captured from the Init dialog box,
208: // convert the name into the proper form; then do a CreateFile()
209: // to connect to the pipe. Handle any error from the CreateFile().
210: // Then write the user name to the server instance of the named
211: // pipe. Finally, create a thread to read the named pipe.
212:
213: // Launch Init dialog box to capture
214: // share name and user name.
215: DialogBox ((HANDLE)GetModuleHandle(NULL),
216: (LPCTSTR)"InitDialog",
217: (HWND)hDlg,
218: (DLGPROC)InitDlgProc);
219:
220: // Put captured user name in window
221: // caption.
222: SetWindowText (hDlg, ClntName);
223:
224: // Construct file/pipe name.
225: wsprintf (fileName, "%s%s%s", "\\\\", ShrName, "\\PIPE\\test");
226:
227: // Do CreateFile() to connect to the
228: // named pipe.
229: hPipe = CreateFile (fileName, // Pipe name.
230: GENERIC_WRITE // Generic access, read/write.
231: | GENERIC_READ,
232: FILE_SHARE_READ // Share both read and write.
233: | FILE_SHARE_WRITE ,
234: NULL, // No security.
235: OPEN_EXISTING, // Fail if not existing.
236: FILE_FLAG_OVERLAPPED, // Use overlap.
237: NULL); // No template.
238:
239: // Do some error checking.
240: if ((DWORD)hPipe == 0xFFFFFFFF)
241: {
242: retCode = GetLastError();
243:
244: // This error means pipe wasn't found.
245: if ((retCode == ERROR_SEEK_ON_DEVICE) ||
246: (retCode == ERROR_FILE_NOT_FOUND))
247: MessageBox (hDlg,
248: "CANNOT FIND PIPE: Assure Server32 is started, check share name.",
249: "",
250: MB_OK);
251: else
252: { // Flagging unknown errors.
253: wsprintf (errorBuf,
254: "CreateFile() on pipe failed, see winerror.h error #%d.",
255: retCode);
256: MessageBox (hDlg, errorBuf, "Debug Window",
257: MB_ICONINFORMATION | MB_OK | MB_APPLMODAL);
258: }
259:
260: EndDialog (hDlg, 0); // Kill app if pipe didn't connect.
261: };
262:
263: // Create and init overlapped structure
264: // for writes.
265: hEventWrt = CreateEvent (NULL, TRUE, FALSE, NULL);
266: OverLapWrt.hEvent = hEventWrt;
267:
268: // Write the client name to server.
269: retCode = WriteFile (hPipe, ClntName, PLEASE_WRITE,
270: &bytesWritten, &OverLapWrt);
271:
272: if (!retCode) // Wait on overlapped if need be.
273: {
274: lastError = GetLastError();
275: if (lastError == ERROR_IO_PENDING)
276: WaitForSingleObject (hEventWrt, (DWORD)-1);
277: }
278: // Create a thread to read the pipe.
279: CreateThread (NULL,
280: 0,
281: (LPTHREAD_START_ROUTINE)ReadPipe,
282: (LPVOID)&hPipe,
283: 0,
284: &threadID);
285: return (0);
286:
287:
288:
289: case WM_INITDIALOG:
290: // PostMessage() give time for the
291: // dialog box to be created.
292: PostMessage (hDlg, WM_INITCLIENT, 0, 0);
293: return (0);
294:
295:
296:
297: case WM_GO_AWAY:
298: CloseHandle (hPipe);
299: CloseHandle (hEventWrt);
300: EndDialog (hDlg, TRUE);
301: return TRUE;
302:
303:
304:
305: case WM_SYSCOMMAND:
306: if (wParam == SC_CLOSE)
307: {
308: CloseHandle (hPipe);
309: CloseHandle (hEventWrt);
310: EndDialog(hDlg, TRUE);
311: return TRUE;
312: }
313: break;
314: }
315: return (FALSE);
316:
317: }
318:
319: /*************************************************************************\
320: *
321: * PROCEDURE: ReadPipe (HANDLE *hRead)
322: *
323: * PURPOSE: This is a thread function which loops and reads the named pipe.
324: *
325: * CALLED BY:
326: *
327: * ClientDlgProc.
328: *
329: *
330: \*************************************************************************/
331:
332: VOID ReadPipe (HANDLE *hPipe)
333: {
334: CHAR inBuf[IN_BUF_SIZE] = "";// Input buffer.
335: DWORD bytesRead; // Used for ReadFile()
336: DWORD retCode; // Used to trap return codes.
337: CHAR Buf[80]; // Message box buffer.
338: DWORD lastError; // Used to trap returns from GetLastError.
339:
340: HANDLE hEventRd; // Event handle for overlapped reads.
341: OVERLAPPED OverLapRd; // Overlapped structure.
342: DWORD bytesTrans; // Bytes transferred in read.
343:
344: // Create and init overlap structure.
345: hEventRd = CreateEvent (NULL, TRUE, FALSE, NULL);
346: memset (&OverLapRd, 0, sizeof(OVERLAPPED));
347: OverLapRd.hEvent = hEventRd;
348:
349: // Loop, reading the named pipe until it is broken. The ReadFile() uses
350: // an overlapped structure. When the event handle signals a completed
351: // read, this loop writes the message to the larger edit field.
352:
353: do{
354: // Read the pipe handle.
355: retCode = ReadFile (*hPipe, inBuf, IN_BUF_SIZE, &bytesRead, &OverLapRd);
356:
357: if (!retCode) // Do some error checking.
358: {
359: lastError = GetLastError();
360: // Check for 3 kinds of errors:
361: // IO_PENDING, BROKEN_PIPE, or
362: // other.
363: // If Error = IO_PENDING, wait for
364: // event handle to signal success.
365: if (lastError == ERROR_IO_PENDING)
366: {
367: WaitForSingleObject (hEventRd, (DWORD)-1);
368:
369: }
370: else // If pipe is broken, tell user and
371: { // break.
372: if (lastError == (DWORD)ERROR_BROKEN_PIPE)
373: MessageBox (hWndClient,
374: "The connection to this client has been broken.",
375: "", MB_OK);
376: else // Or flag unknown errors, and break.
377: {
378: wsprintf (Buf, "ReadFile() on pipe failed, see winerror.h error #%d", GetLastError());
379: MessageBox (hWndClient, Buf, "Client: Debug", MB_OK);
380: }
381: break;
382: }
383: }
384: // NULL terminate string.
385: GetOverlappedResult (*hPipe, &OverLapRd, &bytesTrans, FALSE);
386: inBuf[bytesTrans] = '\0';
387:
388: // Write message to larger edit field.
389: SendMessage (GetDlgItem (hWndClient, IDD_EDITREAD),
390: EM_REPLACESEL,
391: 0, (LONG)inBuf);
392: // Add a new line.
393: SendMessage (GetDlgItem (hWndClient, IDD_EDITREAD),
394: EM_REPLACESEL,
395: 0, (LONG)"\r\n");
396: }while(1);
397:
398: // When pipe is broken, send quit
399: // messages to Client dialog box.
400: PostMessage (hWndClient, WM_GO_AWAY, 0,0);
401: ExitThread(0);
402: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.