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