How to read output from cmd.exe using CreateProcess() and CreatePipe()

后端 未结 6 1804
盖世英雄少女心
盖世英雄少女心 2020-12-09 12:02

How to read output from cmd.exe using CreateProcess() and CreatePipe()

I have been trying to create a child process executing c

6条回答
  •  醉梦人生
    2020-12-09 12:35

    Here is an example (taken from a larger program) of a thread that does what you are looking for. It creates pipes for stdout and stderr for the process it creates then goes into a loop reading those pipes until the program finishes.

    DWORD WINAPI ThreadProc(LPVOID lpParameter)
       {
    #define EVENT_NAME "Global\\RunnerEvt"
    
       HANDLE hev;
       SECURITY_ATTRIBUTES psa;
       InitSAPtr(&psa);
       DWORD waitRc;
       DWORD bytesRead;
       int manual_triggered = 1;
    
       hev = CreateEvent(&psa, FALSE, FALSE, EVENT_NAME);
    
       // Create pipes we'll read
    
          for(;;)
          {
    
          if (manual_triggered)
             {
             waitRc = WAIT_OBJECT_0;
             manual_triggered = 0;
             }
          else
             {
             waitRc = WaitForSingleObject(hev, 500);
             }
    
          if (waitRc == WAIT_OBJECT_0)
             {
             `logprint`f(LOG_DBG, "Received command to run process\n");
    
             CreateChildOutFile();
    
             stdOutEvt = CreateEvent(&psa, TRUE, FALSE, 0);
             stdOutOvl.hEvent = stdOutEvt;
    
             stdErrEvt = CreateEvent(&psa, TRUE, FALSE, 0);
             stdErrOvl.hEvent = stdErrEvt;
    
             gStdOutReadHand =  CreateNamedPipe(STD_OUT_PIPE_NAME, PIPE_ACCESS_DUPLEX + FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE + PIPE_READMODE_BYTE,
                PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &psa);
             if (gStdOutReadHand == INVALID_HANDLE_VALUE)
                {
                log(LOG_DBG, "Error %d on create STDOUT pipe\n", GetLastError());
                }
    
             gStdErrReadHand =  CreateNamedPipe(STD_ERR_PIPE_NAME, PIPE_ACCESS_DUPLEX + FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE + PIPE_READMODE_BYTE,
                PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &psa);
             if (gStdErrReadHand == INVALID_HANDLE_VALUE)
                {
                log(LOG_DBG, "Error %d on create STDERR pipe\n", GetLastError());
                }
    
             runProcess();
    
             log(LOG_DBG, "After runProcess, new PID is %d/%x\n", piProcInfo.dwProcessId, piProcInfo.dwProcessId);
    
             if (piProcInfo.dwProcessId == 0)
                {
                log(LOG_DBG, "runProcess failed, closing child STDIN/STDERR\n");
                closeChildPipes();
    
    #define FAIL_MSG "Child process failed to start\n"
                writeChildOutFile(FAIL_MSG, strlen(FAIL_MSG) );
    
                CloseHandle(hChildOut);
                }
             else
                {
                log(LOG_DBG, "Child process created, setting up for redir/restart/termination\n");
    
                issueRead(gStdOutReadHand, &stdOutOvl, stdOutBuff, &stdOutBytesAvail);
                //log(LOG_DBG, "After read set on STDOUT\n");
    
                issueRead(gStdErrReadHand, &stdErrOvl, stdErrBuff, &stdErrBytesAvail);
                //log(LOG_DBG, "After read set on STDERR\n");
    
                HANDLE harr[4];
    
                for(;;)
                   {
                   harr[0] = hev;
                   harr[1] = piProcInfo.hProcess;
                   harr[2] = stdOutEvt;
                   harr[3] = stdErrEvt;
    
                   DWORD waitRc2 = WaitForMultipleObjects(4, harr, FALSE, 500);
    
                   #if 0
                   if (waitRc2 == -1)
                      {
                      log(LOG_DBG, "Wait error %d\n", GetLastError());
                      Sleep(500);
                      }
    
                   log(LOG_DBG, "waitRc2 %d\n", waitRc2);
                   #endif
    
    
                   if ((waitRc2 - WAIT_OBJECT_0) == 0)
                      {
                      log(LOG_DBG, "Woke up because another trigger command was received\n");
                      #define NEW_CMD_MSG "Child process is being terminated because new trigger received\n"
    
                      writeChildOutFile(NEW_CMD_MSG, strlen(NEW_CMD_MSG));
    
                      terminateChild();
                      CloseHandle(hChildOut);
                      manual_triggered = 1;
                      break;
                      }
                   else if ((waitRc2 - WAIT_OBJECT_0) == 1)
                      {
                      //log(LOG_DBG, "Woke up because child has terminated\n");
                      closeChildPipes();
                      #define NORM_MSG "Normal child process termination\n"
                      writeChildOutFile(NORM_MSG, strlen(NORM_MSG));
                      CloseHandle(hChildOut);
                      break;
                      }
                   else if ((waitRc2 - WAIT_OBJECT_0) == 2)
                      {
                      //log(LOG_DBG, "Woke up because child has stdout\n");
                      if (GetOverlappedResult(gStdOutReadHand, &stdOutOvl, &bytesRead, TRUE))
                         {
                         writeChildOutFile(stdOutBuff, bytesRead);
                         ResetEvent(stdOutEvt);
                         issueRead(gStdOutReadHand, &stdOutOvl, stdOutBuff, &stdOutBytesAvail);
                         }
    
                      }
                   else if ((waitRc2 - WAIT_OBJECT_0) == 3)
                      {
                      //log(LOG_DBG, "Woke up because child has stderr\n");
    
                      if (GetOverlappedResult(gStdErrReadHand, &stdErrOvl, &bytesRead, TRUE))
                         {
                         writeChildOutFile(stdErrBuff, bytesRead);
                         ResetEvent(stdErrEvt);
                         issueRead(gStdErrReadHand, &stdErrOvl, stdErrBuff, &stdErrBytesAvail);
                         }
                      }
                   else
                      {
                      if (gShuttingDown)
                         {
                         log(LOG_DBG, "Woke with active child and service is terminating\n");
    
    #define SHUTDOWN_MSG "Child process is being terminated because the service is shutting down\n"
    
                         writeChildOutFile(SHUTDOWN_MSG, strlen(SHUTDOWN_MSG));
                         terminateChild();
                         CloseHandle(hChildOut);
                         break;
                         }
                      }
    
                   if (gShuttingDown)
                      {
                      break;
                      }
    
                   }
                }
             }
          else if (gShuttingDown)
             {
             break;
             }
    
          CloseHandle(gStdOutReadHand);
          CloseHandle(gStdErrReadHand);
    
          }
    
       return 0;
       }
    
    void writeChildOutFile(char *msg, int len)
       {
       DWORD bytesWritten;
       WriteFile(hChildOut, msg, len, &bytesWritten, 0);
       }
    
    
    void terminateChild(void)
       {
       if (piProcInfo.dwProcessId != 0)
          {
          TerminateProcess(piProcInfo.hProcess, -1);
          CloseHandle(piProcInfo.hThread);
          CloseHandle(piProcInfo.hProcess);
          closeChildPipes();
          }
       }
    
    void closeChildPipes(void)
       {
       CloseHandle(g_hChildStd_OUT_Wr);
       CloseHandle(g_hChildStd_ERR_Wr);
       }
    
    void runProcess(void)
       {
       SECURITY_ATTRIBUTES saAttr;
    
       // Set the bInheritHandle flag so pipe handles are inherited.
       saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
       saAttr.bInheritHandle = TRUE;
       saAttr.lpSecurityDescriptor = NULL;
    
       // Create a pipe for the child process's STDOUT.
       TCHAR szCmdline[]=TEXT("cmd.exe /C C:\\temp\\RunnerService.bat");
       STARTUPINFO siStartInfo;
       BOOL bSuccess = FALSE;
    
    // Set up members of the PROCESS_INFORMATION structure.
    
       ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
    
       g_hChildStd_OUT_Wr = CreateFile (STD_OUT_PIPE_NAME,
                    FILE_WRITE_DATA,
                    0,
                    &saAttr,
                    OPEN_EXISTING,
                    0,
                    NULL);
    
       if (g_hChildStd_OUT_Wr == INVALID_HANDLE_VALUE)
          {
          log(LOG_DBG, "Error creating child proc stdout file %d\n", GetLastError());
          }
    
    
       g_hChildStd_ERR_Wr = CreateFile (STD_ERR_PIPE_NAME,
                    FILE_WRITE_DATA,
                    0,
                    &saAttr,
                    OPEN_EXISTING,
                    0,
                    NULL);
    
       if (g_hChildStd_ERR_Wr == INVALID_HANDLE_VALUE)
          {
          log(LOG_DBG, "Error creating child proc stderr file %d\n", GetLastError());
          }
    
    
    // Set up members of the STARTUPINFO structure.
    // This structure specifies the STDIN and STDOUT handles for redirection.
    
       ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
       siStartInfo.cb = sizeof(STARTUPINFO);
       siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
       siStartInfo.hStdError = g_hChildStd_ERR_Wr;
       siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
    
    // Create the child process.
    
       bSuccess = CreateProcess(NULL,
          szCmdline,     // command line
          NULL,          // process security attributes
          NULL,          // primary thread security attributes
          TRUE,          // handles are inherited
          0,             // creation flags
          NULL,          // use parent's environment
          NULL,          // use parent's current directory
          &siStartInfo,  // STARTUPINFO pointer
          &piProcInfo);  // receives PROCESS_INFORMATION
    
       }
    
    
    void CreateChildOutFile(void)
       {
       SYSTEMTIME st;
       SECURITY_ATTRIBUTES sa;
       char fName[_MAX_PATH];
    
       InitSAPtr(&sa);
    
       GetLocalTime(&st);
    
       sprintf(fName, "C:\\TEMP\\runsvcchild_%02d_%02d_%02d_%04d.out", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
    
       hChildOut = CreateFile(fName, GENERIC_WRITE, FILE_SHARE_READ, &sa,  CREATE_ALWAYS,  FILE_ATTRIBUTE_NORMAL, 0);
       }
    
    void issueRead(HANDLE hFile, OVERLAPPED *overLapped, char *buf, DWORD *dwRead)
       {
       //log(LOG_DBG, "Start of issueRead, hfile %08x, ovl is %08x\n", hFile, overLapped);
       BOOL brc = ReadFile(hFile, buf, 4096, dwRead, overLapped);
       if (!brc)
          {
          DWORD dwle = GetLastError();
          if (dwle != ERROR_IO_PENDING)
             {
             log(LOG_DBG, "Error %d on ReadFile\n", dwle);
             }
          }
       else
          {
          // log(LOG_DBG, "Read issued\n");
          }
       }  
    

提交回复
热议问题