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