Annotation of q_a/samples/inherit/inherit.c, revision 1.1.1.3

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.