|
|
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.