怎样在windows环境中启动某控制台程序并改变它的stdin、stdout和stderr? http://book.77169.org/ask18/how106297.htm

来源:互联网 发布:网络电视机顶盒的安装 编辑:程序博客网 时间:2024/05/01 08:51
?
MSDN里面有一些文档可以看看,方法是利用CreateProcess的 LPSTARTUPINFO 参数,设置dwFlags为STARTF_USESTDHANDLES:然后自定义:HANDLE  hStdInput; HANDLE  hStdOutput; HANDLE  hStdError; 三个流句柄。这些句柄可以用CreatePipe创建的匿名管道句柄代替:BOOL CreatePipe(  PHANDLE hReadPipe,                       // read handle  PHANDLE hWritePipe,                      // write handle  LPSECURITY_ATTRIBUTES lpPipeAttributes,  // security attributes  DWORD nSize                              // pipe size);其中hStdOutput,hStdError传给hWritePipe,hStdInput传给hReadPipe,然后把管道的另一端的句柄保存起来。就可以用ReadFile/WriteFile从这些句柄读取/写入控制台程序的输出/输入。要注意的是这些句柄的继承性,调用CreateProcess时注意设置BOOL bInheritHandles = TRUE,使它可以继承主进程的句柄。调用CreatePipe要设置LPSECURITY_ATTRIBUTES lpPipeAttributes参数使Pipe的句柄能够被继承。此外,这样使CreatePipe创建的两个句柄都可以被继承了,所以要调用DuplicateHandle把不需要传入子进程的句柄设置为不可继承。不然子进程拥有了另一个句柄但是不会调用Closehandle减少引用记数,会导致Pipe不能被在使用完毕后被撤消。此外注意关闭所有使用过的内核对象句柄。以下是MSDN的一个例子:
  1. INHERIT.C
  2. /*******************************************************************************       This is a part of the Microsoft Source Code Samples.  
  3. *       Copyright (C) 1992-1996 Microsoft Corporation. 
  4. *       All rights reserved.  
  5. *       This source code is only intended as a supplement to  
  6. *       Microsoft Development Tools and/or WinHelp documentation. 
  7. *       See these sources for detailed information regarding the  
  8. *       Microsoft samples programs. 
  9. /******************************************************************************/
  10.   
  11. /******************************************************************** 
  12. * This program is to demonstrate the use of anonymous pipes used as * 
  13. * stdout and stderr replacements. One of two techniques can be      * 
  14. * chose to do this: the SetStdHandle technique or the               * 
  15. * STARTF_USESTDHANDLES technique. The SetStdHandle technique sets   * 
  16. * the standard output handles to the pipe that we will read from,   * 
  17. * which the child will inherit. The STARTF_USESTDHANDLES technique  * 
  18. * passes the pipe handles to the child as standard handles via the  * 
  19. * STARTUPINFO structure. The STARTF_USESTDHANDLES technique *must*  * 
  20. * be used for "console-less" processes such as GUI applications or  * 
  21. * detached processes.                                               * 
  22. *                                                                   * 
  23. * This program demonstrates the use of the following Win32 APIs:    * 
  24. *   CreatePipe, CreateProcess.                                      * 
  25. *                                                                   * 
  26. * This program also uses the following Win32 APIs:                  * 
  27. *   GetLastError, CreateFile, CloseHandle, CreateProcess, ReadFile, * 
  28. *   WriteFile.                                                      * 
  29. *                                                                   * 
  30. *                                                                   * 
  31. * Execution instructions:                                           * 
  32. *                                                                   * 
  33. *   inherit <trace file> <command to execute>                       * 
  34. *   trace file is the name of the file where the stdout             * 
  35. *     and stderr of command will be redirected                      * 
  36. *                                                                   * 
  37. *   command to execute can be either an external executable or an   * 
  38. *     internal cmd.exe command.                                     * 
  39. *                                                                   * 
  40. *   Examples:                                                       * 
  41. *                                                                   * 
  42. *   inherit chkdsk.dat chkdsk d:                                    * 
  43. *   inherit nmake.txt nmake /f foo.mak                              * 
  44. *                                                                   * ********************************************************************/  
  45. #include <windows.h> 
  46. #include <stdio.h> 
  47. #include <stdlib.h> 
  48. #include <string.h>  
  49. /* define USESTDHANDLES to use the new technique of passing the 
  50. standard handles to the child process via the STARTUPINFO structure. 
  51. This technique must be used for "console-less" parents such as GUI 
  52. applications or detached applications. */  
  53. #define USESTDHANDLES  
  54. /* Standard error macro for reporting API errors */
  55. //#define PERR(bSuccess, api) {if (!(bSuccess)) printf("%s: Error %d from %s  
  56. //    on line %d/n", __FILE__, GetLastError(), api, __LINE__);}  void PERR(BOOL bSuccess, char * api);  
  57. int main(int argc, char *argv[]) 
  58. {   
  59.   char chReadBuffer[64];  /* pipe read buffer */   
  60.   BOOL bSuccess;  /* BOOL return code for APIs */   
  61.   int j;   
  62.   HANDLE hOutFile;  /* handle to log file */   
  63.   /* handles to the anonymous pipe */   
  64.   HANDLE hReadPipe, hWritePipe, hWritePipe2;   
  65.   char szArgs[256];  /* child process argument buffer */   
  66.   char *p;  /* temporary pointer into szArgs */   
  67.   DWORD cchReadBuffer;  /* number of bytes read or to be written */   
  68.   STARTUPINFO si;  /* for CreateProcess call */   
  69.   PROCESS_INFORMATION pi;  /* for CreateProcess call */   
  70.   SECURITY_ATTRIBUTES saPipe;  /* security for anonymous pipe */   
  71.   OSVERSIONINFO os; /* operating system specs */
  72.     
  73.   os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); // required assignment    
  74.   // check if running on Windows NT, if not, display notice and terminate   
  75.   if ( GetVersionEx(&os) )   
  76.   {       
  77.       if( os.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS &
  78.           os.dwPlatformId != VER_PLATFORM_WIN32_NT)
  79.       {
  80.            MessageBox( NULL,
  81.            "This sample application can only run on Windows NT and Windows 95./n 
  82.            This application will now terminate.", 
  83.            "Inherit"
  84.            MB_OK | MB_ICONSTOP | MB_SETFOREGROUND ); 
  85.            return( 1 ); 
  86.       }
  87.    }
  88.    else
  89.    {
  90.       MessageBox( NULL, 
  91.       "Unable to test for OS version."
  92.       "Inherit Error"
  93.       MB_OK | MB_ICONSTOP | MB_SETFOREGROUND ); 
  94.       return( 1 );
  95.    }
  96.    if (argc < 3) 
  97.    {
  98.      puts("format: inherit <trace file> <command to execute>");
  99.      puts("trace file is the name of the file where the stdout");
  100.      puts("and stderr of command will be redirected/n");
  101.      puts("command to execute is command line of the function");
  102.      puts("you wish to perform./n");
  103.      puts("Examples:/n");
  104.      puts("  inherit trace.txt chkdsk d:");
  105.      puts("  inherit trace.txt nmake /f foo.mak");
  106.      return(1);
  107.    }
  108.    /* create the log file where we will save all output from child */
  109.    hOutFile = CreateFile(argv[1],  /* file to open */
  110.        GENERIC_WRITE,  /* access mode */
  111.        FILE_SHARE_READ,  /* share mode */
  112.        NULL,  /* security attributes */
  113.        CREATE_ALWAYS,  /* creation flags - trash existing file */
  114.        FILE_ATTRIBUTE_NORMAL,  /* file attributes */
  115.        NULL);
  116.    PERR(hOutFile != INVALID_HANDLE_VALUE, "CreateFile");
  117.    /* set up the security attributes for the anonymous pipe */
  118.    saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
  119.    saPipe.lpSecurityDescriptor = NULL;
  120.    /* In order for the child to be able to write to the pipe, the handle */
  121.    /* must be marked as inheritable by setting this flag: */
  122.    saPipe.bInheritHandle = TRUE;
  123.  
  124.    /* create the anonymous pipe */
  125.    bSuccess = CreatePipe(&hReadPipe,  /* read handle */
  126.        &hWritePipe,  /* write handle, used as stdout by child */
  127.        &saPipe,  /* security descriptor */
  128.        0);  /* pipe buffer size */
  129.    PERR(bSuccess, "CreatePipe");
  130.    /* Now we need to change the inheritable property for the readable
  131.    end of the pipe so that the child will not inherit that handle as
  132.    a "garbage" handle. This will keep us from having extra,
  133.    unclosable handles to the pipe. Alternatively, we could have
  134.    opened the pipe with saPipe.bInheritHandle = FALSE and changed the
  135.    inherit property on the *write* handle of the pipe to TRUE. */
  136.    bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */
  137.        hReadPipe, /* handle to duplicate */
  138.        GetCurrentProcess(), /* destination process */
  139.        NULL, /* new handle - don't want one, change original handle */
  140.        0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */
  141.        FALSE, /* make it *not* inheritable */
  142.        DUPLICATE_SAME_ACCESS);
  143.    PERR(bSuccess, "DuplicateHandle");
  144.  
  145.    /* I most cases you can get away with using the same anonymous
  146.    pipe write handle for both the child's standard output and
  147.    standard error, but this may cause problems if the child app
  148.    explicitly closes one of its standard output or error handles. If
  149.    that happens, the anonymous pipe will close, since the child's
  150.    standard output and error handles are really the same handle. The
  151.    child won't be able to write to the other write handle since the
  152.    pipe is now gone, and parent reads from the pipe will return
  153.    ERROR_BROKEN_PIPE and child output will be lost. To solve this
  154.    problem, simply duplicate the write end of the pipe to create
  155.    another distinct, separate handle to the write end of the pipe.
  156.    One pipe write handle will serve as standard out, the other as
  157.    standard error. Now *both* write handles must be closed before the
  158.    write end of the pipe actually closes. */
  159.  
  160.    bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */
  161.        hWritePipe, /* handle to duplicate */
  162.        GetCurrentProcess(), /* destination process */
  163.        &hWritePipe2, /* new handle, used as stderr by child */
  164.        0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */
  165.        TRUE, /* it's inheritable */
  166.        DUPLICATE_SAME_ACCESS);
  167.    PERR(bSuccess, "DuplicateHandle");
  168.  
  169.    /* Set up the STARTUPINFO structure for the CreateProcess() call */
  170.    memset(&si, 0, sizeof(si));
  171.    si.cb = sizeof(si);
  172.  
  173.    /* Set up the command-line buffer for the child for CreateProcess() */
  174.    memset(szArgs, 0, sizeof(szArgs));
  175.    strcpy(szArgs, argv[2]);
  176.    if (strchr(szArgs, '.') == NULL)  /* does it have a '.'? */
  177.      strcat(szArgs, ".exe");  /* if not, assume it's an .exe */
  178.    strcat(szArgs, " ");
  179.    p = strchr(szArgs, 0);  /* point to the terminating null */
  180.    for (j = 3; j < argc; j++)
  181.    {
  182.      strcat(p, argv[j]);
  183.      /* the program and parameters are delimited by spaces */
  184.      strcat(p, " ");
  185.    }
  186.  #ifdef USESTDHANDLES   
  187.    /* If using the STARTUPINFO STARTF_USESTDHANDLES flag, be sure to
  188.    set the CreateProcess fInheritHandles parameter too TRUE so that
  189.    the file handles specified in the STARTUPINFO structure will be
  190.    inheritied by the child. Note that we don't specify a standard
  191.    input handle; the child will not inherit a valid input handle, so
  192.    if it reads from stdin, it will encounter errors. */
  193.  
  194.    si.hStdInput = hWritePipe2; /* hStdInput needs a valid handle in case it is checked by the child */
  195.    si.hStdOutput = hWritePipe; /* write end of the pipe */
  196.    si.hStdError = hWritePipe2; /* duplicate of write end of the pipe */
  197.    si.dwFlags = STARTF_USESTDHANDLES;
  198.  #else
  199.    /* If we're not using the STARTF_USESTDHANDLES flag, set the
  200.    standard output and error handles to the end of the pipe we want
  201.    the child to inherit with SetStdHandle(). For this program, we
  202.    don't want standard input inherited so we'll also change the
  203.    handle inheritance property of standard input so that it is not
  204.    inherited */
  205.    bSuccess = SetStdHandle(STD_INPUT_HANDLE, hWritePipe2);
  206.    PERR(bSuccess, "SetStdHandle");
  207.    bSuccess = SetStdHandle(STD_OUTPUT_HANDLE, hWritePipe);
  208.    PERR(bSuccess, "SetStdHandle");
  209.    bSuccess = SetStdHandle(STD_ERROR_HANDLE, hWritePipe2);
  210.    PERR(bSuccess, "SetStdHandle");
  211.    bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */
  212.        GetStdHandle(STD_INPUT_HANDLE), /* handle to duplicate */
  213.        GetCurrentProcess(), /* destination process */
  214.        NULL, /* new handle - don't want one, change original handle */
  215.        0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */
  216.        FALSE, /* it's *not* inheritable */
  217.        DUPLICATE_SAME_ACCESS);
  218.    PERR(bSuccess, "DuplicateHandle");
  219.  #endif
  220.  
  221.    /* Now create the child process, inheriting handles */
  222.  
  223.    bSuccess = CreateProcess(NULL,  /* filename */
  224.        szArgs,  /* full command line for child */
  225.        NULL,  /* process security descriptor */
  226.        NULL,  /* thread security descriptor */
  227.        TRUE,  /* inherit handles? Also use if STARTF_USESTDHANDLES */
  228.        0,  /* creation flags */
  229.        NULL,  /* inherited environment address */
  230.        NULL,  /* startup dir; NULL = start in current */
  231.        &si,  /* pointer to startup info (input) */
  232.        π);  /* pointer to process info (output) */
  233.    PERR(bSuccess, "CreateProcess");
  234.  
  235.    /* We can close the returned child process handle and thread
  236.    handle as we won't be needing them; you could, however, wait on
  237.    the process handle to wait until the child process terminates. */
  238.  
  239.    CloseHandle(pi.hThread);
  240.    CloseHandle(pi.hProcess);
  241.  
  242.    /* We need to close our instances of the inheritable pipe write
  243.    handle now that it's been inherited so that all open handles to
  244.    the pipe are closed when the child process ends and closes its
  245.    handles to the pipe. */
  246.  
  247.    bSuccess = CloseHandle(hWritePipe);
  248.    PERR(bSuccess, "CloseHandle");
  249.    bSuccess = CloseHandle(hWritePipe2);
  250.    PERR(bSuccess, "CloseHandle");
  251.  
  252.    /* read from the pipe until we get an ERROR_BROKEN_PIPE */
  253.    for (;;)
  254.      {
  255.      bSuccess = ReadFile(hReadPipe,  /* read handle */
  256.          chReadBuffer,  /* buffer for incoming data */
  257.          sizeof(chReadBuffer),  /* number of bytes to read */
  258.          &cchReadBuffer,  /* number of bytes actually read */
  259.          NULL);  /* no overlapped reading */
  260.      if (!bSuccess && (GetLastError() == ERROR_BROKEN_PIPE))
  261.          break;  /* child has died */
  262.  
  263.      PERR(bSuccess, "ReadFile");
  264.      if (bSuccess && cchReadBuffer)
  265.        {
  266.        /* write the data from the child to the file */
  267.        bSuccess = WriteFile(hOutFile,  /* write handle */
  268.            chReadBuffer,  /* buffer to write */
  269.            cchReadBuffer,  /* number of bytes to write */
  270.            &cchReadBuffer,  /* number of bytes actually written */
  271.            NULL);  /* no overlapped writing */
  272.        PERR(bSuccess, "WriteFile");
  273.  
  274.        /* write buffer (of specified length) to console */
  275.        printf("%.*s", cchReadBuffer, chReadBuffer);
  276.        }
  277.      }
  278.    /* close the trace file, pipe handles */
  279.    CloseHandle(hOutFile);
  280.    CloseHandle(hReadPipe);
  281.    return(0);
  282.  }  
  283.  void PERR(BOOL bSuccess, char * api)
  284.  {
  285.      DWORD       dwError;
  286.      TCHAR       szMsgBuf[500];
  287.  
  288.      if (!(bSuccess)) 
  289.      {
  290.          dwError = GetLastError();
  291.          printf("/nFile:%s/nError occured in %s on line %d/n", __FILE__, api, __LINE__);
  292.      FormatMessage(
  293.          FORMAT_MESSAGE_FROM_SYSTEM,
  294.          NULL,                               // ignored
  295.          dwError,                     // message id
  296.          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),   // message language
  297.          szMsgBuf,                   // address of buffer pointer
  298.          500,                                  // minimum buffer size
  299.          NULL );                              // no other arguments
  300.  
  301.          printf("/nError:(%ld)%s ", dwError, szMsgBuf);
  302.       }
  303.  }
  304.   

原创粉丝点击