|
|
1.1.1.3 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: 1.1 root 12: /******************************************************************** 13: * This program is to demonstrate the use of anonymous pipes used as * 1.1.1.3 ! root 14: * stdout and stderr replacements. One of two techniques can be * ! 15: * chose to do this: the SetStdHandle technique or the * ! 16: * STARTF_USESTDHANDLES technique. The SetStdHandle technique sets * ! 17: * the standard output handles to the pipe that we will read from, * ! 18: * which the child will inherit. The STARTF_USESTDHANDLES technique * ! 19: * passes the pipe handles to the child as standard handles via the * ! 20: * STARTUPINFO structure. The STARTF_USESTDHANDLES technique *must* * ! 21: * be used for "console-less" processes such as GUI applications or * ! 22: * detached processes. * 1.1 root 23: * * 24: * This program demonstrates the use of the following Win32 APIs: * 1.1.1.3 ! root 25: * CreatePipe, CreateProcess. * 1.1 root 26: * * 27: * This program also uses the following Win32 APIs: * 28: * GetLastError, CreateFile, CloseHandle, CreateProcess, ReadFile, * 29: * WriteFile. * 30: * * 31: * * 32: * Execution instructions: * 33: * * 34: * inherit <trace file> <command to execute> * 35: * trace file is the name of the file where the stdout * 36: * and stderr of command will be redirected * 37: * * 1.1.1.3 ! root 38: * command to execute can be either an external executable or an * ! 39: * internal cmd.exe command. * 1.1 root 40: * * 41: * Examples: * 42: * * 1.1.1.3 ! root 43: * inherit chkdsk.dat chkdsk d: * ! 44: * inherit nmake.txt nmake /f foo.mak * ! 45: * * 1.1 root 46: ********************************************************************/ 47: 48: #include <windows.h> 49: #include <stdio.h> 50: #include <stdlib.h> 51: #include <string.h> 52: 1.1.1.3 ! root 53: /* define USESTDHANDLES to use the new technique of passing the ! 54: standard handles to the child process via the STARTUPINFO structure. ! 55: This technique must be used for "console-less" parents such as GUI ! 56: applications or detached applications. */ ! 57: ! 58: #define USESTDHANDLES 1.1 root 59: 60: /* Standard error macro for reporting API errors */ 1.1.1.3 ! root 61: #define PERR(bSuccess, api) {if (!(bSuccess)) printf("%s: Error %d from %s \ ! 62: on line %d\n", __FILE__, GetLastError(), api, __LINE__);} 1.1 root 63: 64: int main(int argc, char *argv[]) 65: { 1.1.1.3 ! root 66: char chReadBuffer[64]; /* pipe read buffer */ ! 67: BOOL bSuccess; /* BOOL return code for APIs */ 1.1 root 68: int j; 69: HANDLE hOutFile; /* handle to log file */ 1.1.1.3 ! root 70: /* handles to the anonymous pipe */ ! 71: HANDLE hReadPipe, hWritePipe, hWritePipe2; ! 72: char szArgs[256]; /* child process argument buffer */ ! 73: char *p; /* temporary pointer into szArgs */ ! 74: DWORD cchReadBuffer; /* number of bytes read or to be written */ 1.1 root 75: STARTUPINFO si; /* for CreateProcess call */ 76: PROCESS_INFORMATION pi; /* for CreateProcess call */ 77: SECURITY_ATTRIBUTES saPipe; /* security for anonymous pipe */ 78: 1.1.1.3 ! root 79: /* Check to make sure we are running on Windows NT */ ! 80: if( GetVersion() & 0x80000000 ) ! 81: { ! 82: MessageBox(NULL, "Sorry, this application requires Windows NT.\n" ! 83: "This application will now terminate.", ! 84: "Error: Windows NT Required to Run", MB_OK ); ! 85: return(1); ! 86: } 1.1 root 87: if (argc < 3) 88: { 89: puts("format: inherit <trace file> <command to execute>"); 90: puts("trace file is the name of the file where the stdout"); 91: puts("and stderr of command will be redirected\n"); 1.1.1.3 ! root 92: puts("command to execute is command line of the function"); 1.1 root 93: puts("you wish to perform.\n"); 94: puts("Examples:\n"); 1.1.1.3 ! root 95: puts(" inherit trace.txt chkdsk d:"); ! 96: puts(" inherit trace.txt nmake /f foo.mak"); 1.1 root 97: return(1); 98: } 1.1.1.3 ! root 99: 1.1 root 100: /* create the log file where we will save all output from child */ 101: hOutFile = CreateFile(argv[1], /* file to open */ 102: GENERIC_WRITE, /* access mode */ 103: FILE_SHARE_READ, /* share mode */ 104: NULL, /* security attributes */ 1.1.1.3 ! root 105: CREATE_ALWAYS, /* creation flags - trash existing file */ 1.1 root 106: FILE_ATTRIBUTE_NORMAL, /* file attributes */ 107: NULL); 1.1.1.3 ! root 108: PERR(hOutFile != INVALID_HANDLE_VALUE, "CreateFile"); 1.1 root 109: 1.1.1.3 ! root 110: /* set up the security attributes for the anonymous pipe */ 1.1 root 111: saPipe.nLength = sizeof(SECURITY_ATTRIBUTES); 112: saPipe.lpSecurityDescriptor = NULL; 1.1.1.3 ! root 113: /* In order for the child to be able to write to the pipe, the handle */ ! 114: /* must be marked as inheritable by setting this flag: */ 1.1 root 115: saPipe.bInheritHandle = TRUE; 1.1.1.3 ! root 116: ! 117: /* create the anonymous pipe */ ! 118: bSuccess = CreatePipe(&hReadPipe, /* read handle */ ! 119: &hWritePipe, /* write handle, used as stdout by child */ 1.1 root 120: &saPipe, /* security descriptor */ 1.1.1.3 ! root 121: 0); /* pipe buffer size */ ! 122: PERR(bSuccess, "CreatePipe"); 1.1 root 123: 1.1.1.3 ! root 124: /* Now we need to change the inheritable property for the readable ! 125: end of the pipe so that the child will not inherit that handle as ! 126: a "garbage" handle. This will keep us from having extra, ! 127: unclosable handles to the pipe. Alternatively, we could have ! 128: opened the pipe with saPipe.bInheritHandle = FALSE and changed the ! 129: inherit property on the *write* handle of the pipe to TRUE. */ ! 130: ! 131: bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */ ! 132: hReadPipe, /* handle to duplicate */ ! 133: GetCurrentProcess(), /* destination process */ ! 134: NULL, /* new handle - don't want one, change original handle */ ! 135: 0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */ ! 136: FALSE, /* make it *not* inheritable */ ! 137: DUPLICATE_SAME_ACCESS); ! 138: PERR(bSuccess, "DuplicateHandle"); ! 139: ! 140: /* I most cases you can get away with using the same anonymous ! 141: pipe write handle for both the child's standard output and ! 142: standard error, but this may cause problems if the child app ! 143: explicitly closes one of its standard output or error handles. If ! 144: that happens, the anonymous pipe will close, since the child's ! 145: standard output and error handles are really the same handle. The ! 146: child won't be able to write to the other write handle since the ! 147: pipe is now gone, and parent reads from the pipe will return ! 148: ERROR_BROKEN_PIPE and child output will be lost. To solve this ! 149: problem, simply duplicate the write end of the pipe to create ! 150: another distinct, separate handle to the write end of the pipe. ! 151: One pipe write handle will serve as standard out, the other as ! 152: standard error. Now *both* write handles must be closed before the ! 153: write end of the pipe actually closes. */ ! 154: ! 155: bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */ ! 156: hWritePipe, /* handle to duplicate */ ! 157: GetCurrentProcess(), /* destination process */ ! 158: &hWritePipe2, /* new handle, used as stderr by child */ ! 159: 0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */ ! 160: TRUE, /* it's inheritable */ ! 161: DUPLICATE_SAME_ACCESS); ! 162: PERR(bSuccess, "DuplicateHandle"); ! 163: ! 164: /* Set up the STARTUPINFO structure for the CreateProcess() call */ ! 165: memset(&si, 0, sizeof(si)); ! 166: si.cb = sizeof(si); 1.1 root 167: 1.1.1.3 ! root 168: /* Set up the command-line buffer for the child for CreateProcess() */ ! 169: memset(szArgs, 0, sizeof(szArgs)); ! 170: strcpy(szArgs, argv[2]); ! 171: if (strchr(szArgs, '.') == NULL) /* does it have a '.'? */ ! 172: strcat(szArgs, ".exe"); /* if not, assume it's an .exe */ ! 173: strcat(szArgs, " "); ! 174: p = strchr(szArgs, 0); /* point to the terminating null */ 1.1 root 175: for (j = 3; j < argc; j++) 176: { 1.1.1.3 ! root 177: strcat(p, argv[j]); ! 178: /* the program and parameters are delimited by spaces */ ! 179: strcat(p, " "); 1.1 root 180: } 181: 1.1.1.3 ! root 182: #ifdef USESTDHANDLES ! 183: /* If using the STARTUPINFO STARTF_USESTDHANDLES flag, be sure to ! 184: set the CreateProcess fInheritHandles parameter too TRUE so that ! 185: the file handles specified in the STARTUPINFO structure will be ! 186: inheritied by the child. Note that we don't specify a standard ! 187: input handle; the child will not inherit a valid input handle, so ! 188: if it reads from stdin, it will encounter errors. */ ! 189: ! 190: si.hStdOutput = hWritePipe; /* write end of the pipe */ ! 191: si.hStdError = hWritePipe2; /* duplicate of write end of the pipe */ ! 192: si.dwFlags = STARTF_USESTDHANDLES; ! 193: #else ! 194: /* If we're not using the STARTF_USESTDHANDLES flag, set the ! 195: standard output and error handles to the end of the pipe we want ! 196: the child to inherit with SetStdHandle(). For this program, we ! 197: don't want standard input inherited so we'll also change the ! 198: handle inheritance property of standard input so that it is not ! 199: inherited */ ! 200: ! 201: bSuccess = SetStdHandle(STD_OUTPUT_HANDLE, hWritePipe); ! 202: PERR(bSuccess, "SetStdHandle"); ! 203: bSuccess = SetStdHandle(STD_ERROR_HANDLE, hWritePipe2); ! 204: PERR(bSuccess, "SetStdHandle"); ! 205: bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */ ! 206: GetStdHandle(STD_INPUT_HANDLE), /* handle to duplicate */ ! 207: GetCurrentProcess(), /* destination process */ ! 208: NULL, /* new handle - don't want one, change original handle */ ! 209: 0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */ ! 210: FALSE, /* it's *not* inheritable */ ! 211: DUPLICATE_SAME_ACCESS); ! 212: PERR(bSuccess, "DuplicateHandle"); ! 213: #endif 1.1 root 214: 1.1.1.3 ! root 215: /* Now create the child process, inheriting handles */ ! 216: ! 217: bSuccess = CreateProcess(NULL, /* filename */ ! 218: szArgs, /* full command line for child */ 1.1 root 219: NULL, /* process security descriptor */ 220: NULL, /* thread security descriptor */ 1.1.1.3 ! root 221: TRUE, /* inherit handles? Also use if STARTF_USESTDHANDLES */ 1.1 root 222: 0, /* creation flags */ 223: NULL, /* inherited environment address */ 224: NULL, /* startup dir; NULL = start in current */ 225: &si, /* pointer to startup info (input) */ 226: &pi); /* pointer to process info (output) */ 1.1.1.3 ! root 227: PERR(bSuccess, "CreateProcess"); ! 228: ! 229: /* We can close the returned child process handle and thread ! 230: handle as we won't be needing them; you could, however, wait on ! 231: the process handle to wait until the child process terminates. */ ! 232: 1.1 root 233: CloseHandle(pi.hThread); 234: CloseHandle(pi.hProcess); 1.1.1.3 ! root 235: ! 236: /* We need to close our instances of the inheritable pipe write ! 237: handle now that it's been inherited so that all open handles to ! 238: the pipe are closed when the child process ends and closes its ! 239: handles to the pipe. */ ! 240: ! 241: bSuccess = CloseHandle(hWritePipe); ! 242: PERR(bSuccess, "CloseHandle"); ! 243: bSuccess = CloseHandle(hWritePipe2); ! 244: PERR(bSuccess, "CloseHandle"); ! 245: ! 246: /* read from the pipe until we get an ERROR_BROKEN_PIPE */ ! 247: for (;;) ! 248: { ! 249: bSuccess = ReadFile(hReadPipe, /* read handle */ ! 250: chReadBuffer, /* buffer for incoming data */ ! 251: sizeof(chReadBuffer), /* number of bytes to read */ ! 252: &cchReadBuffer, /* number of bytes actually read */ 1.1 root 253: NULL); /* no overlapped reading */ 1.1.1.3 ! root 254: if (!bSuccess && (GetLastError() == ERROR_BROKEN_PIPE)) ! 255: break; /* child has died */ ! 256: PERR(bSuccess, "ReadFile"); ! 257: if (bSuccess && cchReadBuffer) 1.1 root 258: { 1.1.1.3 ! root 259: /* write the data from the child to the file */ ! 260: bSuccess = WriteFile(hOutFile, /* write handle */ ! 261: chReadBuffer, /* buffer to write */ ! 262: cchReadBuffer, /* number of bytes to write */ ! 263: &cchReadBuffer, /* number of bytes actually written */ 1.1 root 264: NULL); /* no overlapped writing */ 1.1.1.3 ! root 265: PERR(bSuccess, "WriteFile"); 1.1 root 266: 267: /* write buffer (of specified length) to console */ 1.1.1.3 ! root 268: printf("%.*s", cchReadBuffer, chReadBuffer); 1.1 root 269: } 1.1.1.3 ! root 270: } 1.1 root 271: /* close the trace file, pipe handles */ 272: CloseHandle(hOutFile); 273: CloseHandle(hReadPipe); 274: return(0); 275: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.