|
|
1.1 root 1: /********************************************************************
2: * This program is to demonstrate the use of anonymous pipes used as *
3: * stdout and stderr replacements. *
4: * *
5: * This program demonstrates the use of the following Win32 APIs: *
6: * CreatePipe, SetStdHandle. *
7: * *
8: * This program also uses the following Win32 APIs: *
9: * GetLastError, CreateFile, CloseHandle, CreateProcess, ReadFile, *
10: * WriteFile. *
11: * *
12: * *
13: * Execution instructions: *
14: * *
15: * inherit <trace file> <command to execute> *
16: * trace file is the name of the file where the stdout *
17: * and stderr of command will be redirected *
18: * *
19: * command to execute is command line image of the function *
20: * you wish to perform. *
21: * *
22: * Examples: *
23: * *
24: * inherit trace.txt cl386 foo *
25: * inherit trace.txt nmake foo *
26: ********************************************************************/
27:
1.1.1.2 ! root 28: /* Microsoft Developer Support
! 29: Copyright (c) 1992 Microsoft Corporation */
! 30:
1.1 root 31: #include <windows.h>
32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <string.h>
35:
36: #define HSTDOUT 1 /* system handle for stderr */
37: #define HSTDERR 2 /* read pipe handle */
38:
39: /* Standard error macro for reporting API errors */
40: #define PERR(api) printf("%s: Error %d from %s on line %d\n", \
41: __FILE__, GetLastError(), api, __LINE__);
42:
43: int main(int argc, char *argv[])
44: {
45: char bReadBuffer[64]; /* pipe read buffer */
46: BOOL fSuccess; /* BOOL return code for APIs */
47: int j;
48: HANDLE hOutFile; /* handle to log file */
49: HANDLE hReadPipe, hWritePipe; /* handles to the anonymous pipe */
50: char bArgBuffer[256]; /* child process argument buffer */
51: DWORD cbReadBuffer; /* number of bytes read or to be written */
52: STARTUPINFO si; /* for CreateProcess call */
53: PROCESS_INFORMATION pi; /* for CreateProcess call */
54: char *tpARG;
55: SECURITY_ATTRIBUTES saPipe; /* security for anonymous pipe */
56:
57: if (argc < 3)
58: {
59: puts("format: inherit <trace file> <command to execute>");
60: puts("trace file is the name of the file where the stdout");
61: puts("and stderr of command will be redirected\n");
62: puts("command to execute is command line image of the function");
63: puts("you wish to perform.\n");
64: puts("Examples:\n");
65: puts(" inherit trace.txt cl386 foo");
66: puts(" inherit trace.txt nmake foo");
67: return(1);
68: }
69: /* create the log file where we will save all output from child */
70: hOutFile = CreateFile(argv[1], /* file to open */
71: GENERIC_WRITE, /* access mode */
72: FILE_SHARE_READ, /* share mode */
73: NULL, /* security attributes */
74: CREATE_ALWAYS, /* creation flags */
75: FILE_ATTRIBUTE_NORMAL, /* file attributes */
76: NULL);
77: if (hOutFile == (HANDLE) -1)
78: PERR("CreateFile");
79:
80: /******************************************************************
81: * DosMakePipe(&hReadPipe, *
82: * &hWritePipe, *
83: * 0); *
84: * *
85: * The OS/2 DosMakePipe call will be replaced by the Win32 *
86: * CreatePipe call. One important difference between these two *
87: * calls is the addition of the security attribute with *
88: * CreatePipe. In order for the child process to be able to write *
89: * to the anonymous pipe, the handle must be marked as inheritable *
90: * by child processes by setting the *
91: * SECURITY_ATTRIBUTES.bInheritHandle flag to TRUE. *
92: ******************************************************************/
93:
94: saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
95: saPipe.lpSecurityDescriptor = NULL;
96: saPipe.bInheritHandle = TRUE;
97: fSuccess = CreatePipe(&hReadPipe, /* read handle */
98: &hWritePipe, /* write handle */
99: &saPipe, /* security descriptor */
100: 0); /* use default pipe buffer size */
101: if (!fSuccess)
102: PERR("CreatePipe");
103:
104: /*******************************************************************
105: * hOldHandle = HSTDOUT; *
106: * DosDupHandle(hWritePipe, *
107: * &hOldHandle); *
108: * hOldHandle = HSTDERR; *
109: * DosDupHandle(hWritePipe, *
110: * &hOldHandle); *
111: * DosClose(hWritePipe); *
112: * *
113: * Now we must set standard out and standard error to the write end *
114: * of the pipe. Rather than using the OS/2 method of duplicating *
115: * the standard output handle onto the pipe handle, in Win32 all we *
116: * need to do is to set the standard handle to the pipe via *
117: * SetStdHandle. Once standard out and standard error are set to *
118: * the pipe handle, we must close the pipe handle so that when the *
119: * child process dies, the write end of the pipe will close, *
120: * setting an EOF condition on the pipe. *
121: *******************************************************************/
122:
123: fSuccess = SetStdHandle(STD_OUTPUT_HANDLE, hWritePipe);
124: if (!fSuccess)
125: PERR("SetStdHandle");
126:
127: fSuccess = SetStdHandle(STD_ERROR_HANDLE, hWritePipe);
128: if (!fSuccess)
129: PERR("SetStdHandle");
130:
131: /* start the child process; set up the command-line buffer */
132: memset(bArgBuffer, 0, sizeof(bArgBuffer));
133: strcpy(bArgBuffer, argv[2]);
134: if (strchr(bArgBuffer, '.') == NULL) /* does it have a '.'? */
135: strcat(bArgBuffer, ".exe"); /* if not, assume it's an .exe */
136:
137: /*****************************************************************
138: * tpARG = strchr(bArgBuffer, 0) + 1; *
139: * *
140: * This will point one past the terminating null in the buffer. *
141: * *
142: * In the OS/2 version, the first parameter of the command line, *
143: * the program name, must be separated from the rest of the *
144: * parameters by a null. The rest of the parameters would be *
145: * separated by spaces. In the Win32 version, the program name is *
146: * separated from the parameters by a *space*, not a null. *
147: *****************************************************************/
148:
149: strcat(bArgBuffer, " ");
150: tpARG = strchr(bArgBuffer, 0);
151:
152: for (j = 3; j < argc; j++)
153: {
154: strcat(tpARG, argv[j]);
155: strcat(tpARG, " ");
156: }
157:
158: /******************************************************************
159: * DosExecPgm(bObjectBuffer, *
160: * sizeof(bObjectBuffer), *
161: * 1, *
162: * bArgBuffer, *
163: * NULL, *
164: * &bResultCodes, *
165: * bPath); *
166: * DosClose(HSTDOUT); *
167: * DosClose(HSTDERR); *
168: * *
169: * Replace the OS/2 DosExecPgm call with Win32 CreateProcess. Be *
170: * sure to set the fInheritHandles parameter to TRUE so that open *
171: * file handles will be inheritied. We can close the child process *
172: * and thread handles as we won't be needing them. The child *
173: * process will not die until these handles are closed. Also note *
174: * that we don't need to close the standard handles in the Win32 *
175: * version since we did not duplicate the handles but rather set *
176: * the standard handles directly without duplicating them. *
177: ******************************************************************/
178:
179: memset(&si, 0, sizeof(si));
180: si.cb = sizeof(si);
181: fSuccess = CreateProcess(NULL, /* filename */
182: bArgBuffer, /* full command line for child */
183: NULL, /* process security descriptor */
184: NULL, /* thread security descriptor */
185: TRUE, /* inherit handles? */
186: 0, /* creation flags */
187: NULL, /* inherited environment address */
188: NULL, /* startup dir; NULL = start in current */
189: &si, /* pointer to startup info (input) */
190: &pi); /* pointer to process info (output) */
191: if (!fSuccess)
192: PERR("CreateProcess");
193: CloseHandle(pi.hThread);
194: CloseHandle(pi.hProcess);
195: /* We need to close our instance of the inherited pipe write
196: handle now that it's been inherited so that it will actually
197: close when the child process ends. This will put an EOF
198: condition on the pipe which we can then detect. */
199: fSuccess = CloseHandle(hWritePipe);
200: if (!fSuccess)
201: PERR("CloseHandle");
202:
203: /* read from the pipe until EOF condition reached*/
204: do {
205:
206: /************************************************************
207: * DosRead(hReadPipe, *
208: * bReadBuffer, *
209: * sizeof(bReadBuffer), *
210: * &cbReadBuffer); *
211: * *
212: * Replace the OS/2 DosRead calls with ReadFile calls. These *
213: * calls are very similar. *
214: ************************************************************/
215:
216: fSuccess = ReadFile(hReadPipe, /* read handle */
217: bReadBuffer, /* buffer for incoming data */
218: sizeof(bReadBuffer), /* number of bytes to read */
219: &cbReadBuffer, /* number of bytes actually read */
220: NULL); /* no overlapped reading */
221: if (!fSuccess)
222: if (GetLastError() == ERROR_BROKEN_PIPE)
223: break; /* child has died */
224: else
225: PERR("ReadFile");
226: if (fSuccess && cbReadBuffer)
227: {
228:
229: /***************************************************
230: * DosWrite(hOutFile, *
231: * bReadBuffer, *
232: * cbReadBuffer, *
233: * &cbReadBuffer); *
234: * *
235: * Replace the DosWrite calls with WriteFile calls. *
236: ***************************************************/
237:
238: fSuccess = WriteFile(hOutFile, /* write handle */
239: bReadBuffer, /* buffer to write */
240: cbReadBuffer, /* number of bytes to write */
241: &cbReadBuffer, /* number of bytes actually written */
242: NULL); /* no overlapped writing */
243: if (!fSuccess)
244: PERR("WriteFile");
245:
246: /***************************************************************
247: * VioWrtTTY(bReadBuffer, *
248: * cbReadBuffer, *
249: * 0); *
250: * *
251: * Since we didn't do any duplication of standard handles in *
252: * the Win32 version, but rather simply set the standard output *
253: * handle for the child process to the pipe, we can still use *
254: * the standard handles in the parent process, unlike the OS/2 *
255: * version, which must use VioWrtTTY to output to the screen. *
256: ***************************************************************/
257:
258: /* write buffer (of specified length) to console */
259: printf("%.*s", cbReadBuffer, bReadBuffer);
260: }
261: } while (fSuccess && cbReadBuffer);
262: /* close the trace file, pipe handles */
263: CloseHandle(hOutFile);
264: CloseHandle(hReadPipe);
265: return(0);
266: }
267:
268:
269:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.