Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Захват консольного приложения вывод в мемо

76K
09 августа 2013 года
updaite
8 / / 09.08.2013
Программа выводить текст с консоли в Memo, но только после завершения консольного приложения.
Как сделать вывод в реальном времени?

Код:
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
#define READ_BUFFER_SIZE 1024
String AppName = "E:\\1.exe"; // Консольное приложение
SECURITY_ATTRIBUTES Security;
HANDLE ReadPipe, WritePipe;
STARTUPINFO Start;
TProcessInformation ProcessInfo;
char *Buffer, Data;
DWORD BytesRead, Apprunning;
int Result, DataSize;
 
Security.nLength = sizeof(TSecurityAttributes);
Security.bInheritHandle = true;
Security.lpSecurityDescriptor = NULL;
 
if (CreatePipe(&ReadPipe, &WritePipe, &Security, 0))
  {
  Buffer = new char[READ_BUFFER_SIZE + 1];
 
  memset(&Start, 0, sizeof(Start));
  Start.cb = sizeof(Start) ;
  Start.hStdOutput = WritePipe;
  Start.hStdInput = ReadPipe;
  Start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  Start.wShowWindow = SW_HIDE;
 
  if (CreateProcess(NULL, AppName.c_str(), &Security, &Security, true, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, NULL, NULL, &Start, &ProcessInfo))
    {
    do
      {
      Apprunning = WaitForSingleObject(ProcessInfo.hProcess, 100);
      Application->ProcessMessages();
      // вычитываем данные работающей консоли
      do
        {
        Result = PeekNamedPipe(ReadPipe, NULL, 0, NULL, (LPDWORD) &DataSize, NULL);
        if ((Result) && (DataSize))
          {
          if (DataSize > READ_BUFFER_SIZE) DataSize = READ_BUFFER_SIZE;
          ReadFile(ReadPipe, Buffer, DataSize, &BytesRead, NULL);
          Buffer[BytesRead] = 0;
          OemToAnsi(Buffer, Buffer);
          Memo->Text = Memo->Text + (AnsiString) Buffer;
          }
        }
      while ((Result) && (DataSize));
      }
    while (Apprunning == WAIT_TIMEOUT);
    }
 
  delete [] Buffer;
 
  CloseHandle(ProcessInfo.hProcess);
  CloseHandle(ProcessInfo.hThread);
  CloseHandle(ReadPipe);
  CloseHandle(WritePipe);
  }
}
414
09 августа 2013 года
CassandraDied
763 / / 24.05.2012
А код приложения есть?
76K
09 августа 2013 года
updaite
8 / / 09.08.2013
Кода нету, приложение сторонние.
446
10 августа 2013 года
Meander
487 / / 04.09.2011
Заменить внутренний цикл на таймер. По ходу мемо не перерисовывается в таком цикле.
76K
10 августа 2013 года
updaite
8 / / 09.08.2013
С memo все норм, проблема актуальна.
11K
10 августа 2013 года
xAtom
65 / / 17.01.2011
Чтобы было в реальном времени, стороннее приложение должно постоянно сбрасывать output-буфер fflush(stdout) или вообще отключить выходной буфер, если в консольном приложение этого не предусмотрел разработчик, значит получать данные будешь только в конце работы.
76K
10 августа 2013 года
updaite
8 / / 09.08.2013
Пример реализации можно?
446
10 августа 2013 года
Meander
487 / / 04.09.2011
Родительский процесс

Код:
//---------------------------------------------------------------------------
#define bzero(a) memset(a,0,sizeof(a))
#include <string>
typedef std::string xStr;
//---------------------------------------------------------------------------
class ExecOutProc {
  private:
    STARTUPINFO          si;
    PROCESS_INFORMATION  pi;
    SECURITY_ATTRIBUTES  sa;
    SECURITY_DESCRIPTOR  sd;//структура security для пайпов
    HANDLE               newstdin,
                         newstdout,
                         read_stdout,
                         write_stdin;//дескрипторы пайпов
    char                *buffer,
                        *cmdline;
    unsigned long        bread,//кол-во прочитанных байт
                         avail;//кол-во доступных байт
  public:
         ExecOutProc(char*);
        ~ExecOutProc(void);
   void  StartProc(void);
   xStr  ReadOut(void);
};
//------------------------------------
ExecOutProc::ExecOutProc(char* cmd){
  cmdline                 = new char [512];
  strcpy(cmdline,cmd);
  ZeroMemory(&si,sizeof(si));
  si.cb                   = sizeof(si);
  ZeroMemory(&pi,sizeof(pi));
  buffer                  = new char [1024];//|1024|2048|4096|8192|16384|32768|
  sa.lpSecurityDescriptor = NULL;
  sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
  sa.bInheritHandle       = true;//разрешаем наследование дескрипторов
  CreatePipe(&newstdin,&write_stdin,&sa,0);//создаем пайп для stdin
  CreatePipe(&read_stdout,&newstdout,&sa,0);//создаем пайп для stdout
  GetStartupInfo(&si);//создаем startupinfo для дочернего процесса
  si.dwFlags              = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
  si.wShowWindow          = SW_SHOW;//SW_HIDE;
  si.hStdOutput           = newstdout;
  si.hStdError            = newstdout;//подменяем дескрипторы для
  si.hStdInput            = newstdin;// дочернего процесса
}
//------------------------------------
ExecOutProc::~ExecOutProc(void){
  delete [] buffer;
  delete [] cmdline;
// Закроем дескрипторы процесса и потока.
  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);
  CloseHandle(newstdin);//небольшая уборка за собой
  CloseHandle(newstdout);
  CloseHandle(read_stdout);
  CloseHandle(write_stdin);
}
//------------------------------------
void ExecOutProc::StartProc(void){
  if(!CreateProcess(0,cmdline,0,0,1,0,0,0,&si,&pi )){
    CloseHandle(newstdin);
    CloseHandle(newstdout);
    CloseHandle(read_stdout);
    CloseHandle(write_stdin);
  }
}
//------------------------------------
xStr ExecOutProc::ReadOut(void){
  xStr result;
  // Ждать до тех пор, пока дочерний процесс не выйдет из работы.
  WaitForSingleObject(pi.hProcess,50);// 10 INFINITE
  //WaitForInputIdle(pi.hProcess,50);//INFINITE
  bzero(buffer);
  PeekNamedPipe(read_stdout,buffer,1023,&bread,&avail,NULL);
  //Проверяем, есть ли данные для чтения в stdout
  if(bread != 0){
    bzero(buffer);
    if(avail > 1023){
      while (bread >= 1023){
        ReadFile(read_stdout,buffer,1023,&bread,NULL);//читаем из пайпа stdout
        result += buffer;
        bzero(buffer);
      }
    } else {
      ReadFile(read_stdout,buffer,1023,&bread,NULL);
      result += buffer;
      bzero(buffer);
    }
  }
  return result;
}
//---------------------------------------------------------------------------
ExecOutProc *ep;
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  //Получение и печать сообщения
  AnsiString str = AnsiString(ep->ReadOut().c_str());
  if(str.Length())
  Memo1->Lines->Add(str);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ToolButton2Click(TObject *Sender)
{
  //Создаем экземпляр и запускаем приложение
  ep = new ExecOutProc("test.exe");
  ep->StartProc();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ToolButton3Click(TObject *Sender)
{
  //Пуск/Останов чтения пайпа
  Timer1->Enabled = !Timer1->Enabled;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  if(ep) delete ep;
}
//---------------------------------------------------------------------------
Дочерний процесс

Код:
#include <iostream>
#include <clocale>
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
//------------------------------------------------------------------
int main(int argc, char *argv[]) {
  setlocale(LC_ALL,"Rus");
 
  std::cout << "Русский текст.\n\n";
 
  for(int i=0;i<250;i++){
    std::cout << i << "\n";
    Sleep(50);
    fflush(stdout);
  }

  system("pause");
  return 0;
}
//------------------------------------------------------------------
Без fflush(stdout); содержимое потока выводится нормально, после завершения дочернего процесса. С использованием fflush(stdout); онлайн перехват есть, но он не соответствует содержимому потока вывода.
76K
11 августа 2013 года
updaite
8 / / 09.08.2013
Спасибо, за помощь! Того чего я хочу в природе не существует.
7
11 августа 2013 года
@pixo $oft
3.4K / / 20.09.2006
Цитата: xAtom
отключить выходной буфер, если в консольном приложение этого не предусмотрел разработчик, значит получать данные будешь только в конце работы.

Можно инжектнуться в приложение и отключить его изнутри.

76K
11 августа 2013 года
updaite
8 / / 09.08.2013
Цитата: @pixo $oft
Цитата: xAtom
отключить выходной буфер, если в консольном приложение этого не предусмотрел разработчик, значит получать данные будешь только в конце работы.

Можно инжектнуться в приложение и отключить его изнутри.


Каким образом куда копать?

7
13 августа 2013 года
@pixo $oft
3.4K / / 20.09.2006
Читай сообщение xAtom. Я сам таким пока не занимался.
А ещё не оверквоть сообщения — выглядит просто жутчайше, причём чем дальше, тем хуже.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог