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

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:                   

unix.superglobalmegacorp.com

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