如何获得正在运行的进程的实时输出?

时间:2016-08-25 08:25:39

标签: c++ qt

我想获得正在运行的进程的实时输出。因此我在stdout,stdin和stderr的ExecuteCommand()管道中创建了。之后我开始了一个过程,并在一秒后发送QTimer::singleShot()执行CheckOutput()。代码:

bool CommandExecutor_C::ExecuteCommand(QString &aCommand)
{
  aCommand.push_front(std::getenv("ComSpec") + QString(" /c "));
  mCommand = aCommand;
  LOGINFO(FB_TDI,"Launch command: " + aCommand.toStdString());

  SECURITY_ATTRIBUTES secattr;
  ZeroMemory(&secattr,sizeof(secattr));
  secattr.nLength = sizeof(secattr);
  secattr.bInheritHandle = TRUE;

  //in/out/err Handle
  HANDLE StdInHandleRd, StdInHandleWr;//[0] read -> [1] write
  HANDLE StdOutHandleRd, StdOutHandleWr;
  HANDLE StdErrHandleRd, StdErrHandleWr;

  //creating pipes to have access to handle contents
  CreatePipe(&StdInHandleRd , &StdInHandleWr  , &secattr, 4096);
  CreatePipe(&StdOutHandleRd, &StdOutHandleWr , &secattr, 4096);
  CreatePipe(&StdErrHandleRd, &StdErrHandleWr , &secattr, 4096);

  //information for process
  STARTUPINFO si;
  PROCESS_INFORMATION pi;

  ZeroMemory( &si, sizeof(si) );
  si.cb = sizeof(si);

  si.dwFlags |= STARTF_USESTDHANDLES;
  si.hStdInput = StdInHandleRd;   /**< read handle/pipe */
  si.hStdOutput = StdOutHandleWr; /**< write handle/pipe */
  si.hStdError = StdErrHandleWr;  /**< write handle/pipe */

  mHandles.StdOutHandle = StdOutHandleRd;
  mHandles.StdErrHandle = StdErrHandleRd;

  LPWSTR cmdTmp = reinterpret_cast<LPWSTR>(aCommand.data());

  //creates process
  bool res = CreateProcess(NULL,
                           cmdTmp, //command casted to LPWSTR
                           NULL,  // process security attributes
                           NULL,  // primary thread security attributes
                           TRUE,  // handles are inherited
                           NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,
                           NULL,  // use parent's environment
                           NULL,  // use parent's current directory
                           &si,   // STARTUPINFO pointer
                           &pi);  // receives PROCESS_INFORMATION

  if(!res)  //not successfully created
  {
    LOGERROR(FB_TDI,"Failed to create Process for cmd: " + aCommand.toStdString() + boost::lexical_cast<std::string>(GetLastError()));

    CloseHandle(StdInHandleRd);
    CloseHandle(StdInHandleWr);
    CloseHandle(StdOutHandleRd);
    CloseHandle(StdOutHandleWr);
    CloseHandle(StdErrHandleRd);
    CloseHandle(StdErrHandleWr);
    return false; //failed
  }
  else
  {
    DWORD bytesWritten;
    //wait for 1 second
    QTimer::singleShot(1000, this, SLOT(CheckOutput()));
  }

  return true;
}

void CommandExecutor_C::CheckOutput()
{
    QString StdOut;
    QString StdErr;

    //Logs Process output
    LogProcessOutput(mHandles.StdOutHandle, StdOut);
    //Logs Process error
    LogProcessOutput(mHandles.StdErrHandle, StdErr);

    mProcessStatus = CheckTdiAutomationInterface(StdOut.toStdString(), StdErr.toStdString());

    if(mProcessStatus == AI_UNKNOWN)
    {
      //check output again 1 second later
      QTimer::singleShot(1000, this, SLOT(CheckOutput()));
    }
    else
    {
      OnTdiActive(mProcessStatus);
    }
}

提示::函数CheckTdiAutomationInterface()只是将给定字符串与其他一些已定义的字符串进行比较,然后返回进程状态。

但问题似乎出现在LogProcessOutput()中。该函数被调用,但PeekNamedPipe()总是返回0字节可用。仅当进程已完成时,字节才可用。因此,似乎进程输出被缓冲并仅在进程完成时发送到stdout。代码:

void CommandExecutor_C::LogProcessOutput(HANDLE &aReadOutHandle, QString &aProcessOutput)
{
  //Copy data from pipe
  DWORD bytesAvailable = 0;

  if(!PeekNamedPipe(aReadOutHandle,NULL,0,NULL,&bytesAvailable,NULL))
  {
    LOGERROR(FB_TDI,"Failed to call PeekNamedPipe to print process output");
  }

  if(bytesAvailable)
  {
    DWORD dwRead;
    char chBuf[BUFSIZ];
    bool bSuccess = FALSE;
    std::string out;
    do
    {
      //blocks process and waits for more data, this cause errors because no more data is produced
      //thats why PeekNamedPipe should look before if data is available
      bSuccess=::ReadFile( aReadOutHandle, chBuf, BUFSIZ, &dwRead, NULL);

      std::string s(chBuf, dwRead);
      out += s;

      //1. when the last read was successful
      //2. when there is more data available then the bufsize size
      //3. when the read bytes are not less then the BUFSIZE > would mean no more data..
    }
    while( bSuccess && (bytesAvailable>BUFSIZ) && !(dwRead<BUFSIZ) );

    LOGINFO(FB_TDI,"OUTHANDLE:\n"+out);
    aProcessOutput = QString::fromStdString(out);
  }
  else
  {
    aProcessOutput = "";
  }
}

编辑:我想在进程运行时获取输出。如果Process已经完成,一切正常,输出就可以读出来。

0 个答案:

没有答案