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