GARANTIR DESCONTO

Fórum Redirecionar STDOUT de programas console #243908

21/07/2004

0

Boa tarde amigos,

Gostaria de saber se existe alguma maneira de redirecionar a saída padrão de programas que rodam em modo console para outro tipo de stream.

No meu caso, queria redirecionar a saída de programas como o gbak e o gfix para um handle e deste handle capturar as linhas retornadas, utilizando-as em algum outro componente.

Sei que existe uma opção de gravação do log, mas ocorre um erro quando eu abro o arquivo quando o mesmo está sendo gravado.


Se possível, postem um exemplo.


Danilo Christiano


Danilo Christiano

Danilo Christiano

Responder

Posts

21/07/2004

Danilo Christiano

Nota:

Os programas externos são chamados através da função CreateProcess da API do windows e creio que utilizando o parâmetro hStdOutput da estrutura STARTUPINFO (que é um parâmetro da função CreateProcess) posso conseguir este redirecionamento.

Caso alguém saiba utilizar estas funções, poste algum exemplo.


Danilo Christiano


Responder

Gostei + 0

21/07/2004

Beppe

Sim, é por aí. Procure por estas palavras-chave aqui que vc acha.


Responder

Gostei + 0

31/07/2004

Vinicius2k

Danilo, vc solucionou isso?

Eu tentei de tudo e não consegui... por fim pedi que a rotina deletasse o arquivo de log antes de criar o processo (estou usando exatamente para o GBAK)...
if FileExists(´nome_do_log´) then DeleteFile(´nome_do_log´);


Outro problema que enfrento é que o GBAK, ou tem saída no vídeo ou no log... então, se eu coloco a saída para o vídeo, se o banco for pequeno o usuário nem vê a janela e se eu coloco para o arquivo de log, se o banco for grande, fica a ´tela preta´ até terminar o processo...
E outra, tentei amenizar essa ´tela preta´ que no Win 2K é tela cheia, tendando determinar que fosse em janela, designando, posição, tamanho e outras coisas e simplesmente não tenho resultado... não importa os valores de parametros que eu passe para STARTUPINFO que o console sempre é executado em tela cheia...

Se alguém tiver alguma idéia será muito bem vinda...

T+


Responder

Gostei + 0

31/07/2004

Nildo

Estes programas são 32 ou 16 bits? Se forem 32 vocês podem hookar as APIs que ele utiliza para escrever na tela e redirecionar o texto para seu aplicativo.


Responder

Gostei + 0

31/07/2004

Vinicius2k

O GBAK é 32 bits... ele usa a API do Firebird e eu até já estou estudando-a e espero conseguir criar meu sistema de back-up para o Firebird...

Fiz aqui uma coisa que amenizou o problema... continuo direcionando a saída para o Log (e isso é realmente o que eu desejo), mas como o GBAK não dá nenhuma saída do vídeo, fiz uma aplicação console para servir de intermediária, que dá um WriteLn na tela com uma mensagem de ´Executando processo blá blá´ e eh este console que chama o GBAK... assim que termina exibo o Log já dentro da aplicação original...

T+


Responder

Gostei + 0

31/07/2004

Nildo

Seria legal se desse para mostrar exatamente o que está acotnecendo no momento certo né? É possível sim. Só é preciso saber se esses programas utilizam alguma API pra escrever na tela. Qual função eles utilizam pra escrever na tela?


Responder

Gostei + 0

31/07/2004

Vinicius2k

Seria legal se desse para mostrar exatamente o que está acotnecendo no momento certo né?

Com certeza :D
Na boa... eu vou até postar isso para dos devs do Firebird...
o param -v determina que eu quero ´verbose´ para me mostrar na tela...
dae se eu quiser um log eu uso -y + nome do log, só que não dá o verbose em conjunto na tela... pq não os dois... não deve ser nada de tão absurdo assim de fazer...

Só é preciso saber se esses programas utilizam alguma API pra escrever na tela. Qual função eles utilizam pra escrever na tela?

Eu ainda estou estudando e não sei lhe responder isso nildo... mas a documentação é essa : http://www.ibphoenix.com/downloads/60ApiGuide.zip

T+


Responder

Gostei + 0

02/08/2004

Danilo Christiano

Bom,

Utilizar o arquivo de log criado por um determinado programa (via função específica, como -verbose) ou utilizar a interface do programa (como as funções dos nossos ib´s e fb´s) não deixa de ser uma solução prática e eficiente.

Mas, se eu precisar utilizar o retorno de outros programas??? Vou precisar estudar a ducumentação de quantos programas forem necessários, como o ping e o ftp nativos do Windows, sempre???

Seria bacana se eu pudesse chamar qualquer programa console e via a API do Windows direcionar a saída deste para onde eu bem entendesse.

Procurei posts sobre este tópico no fórum, como Beppe me sugeriu. Encontrei saídas e sugestões que eu havia pensado antes, modificando o parâmetro hStdOutput da função startupinfo. Não sei se é pelo meu S.O. (win2000) ou é algum erro de código, mas não consigo fazer a saída ser redirecionada.

Mudo a cor do console para azul, vermelho, cor de fonte, crio o arquivo de log temporário... Faço tudo que é necessário, mas não funciona!!!


Caso alguem consiga fazer o redirecionamento funcionar sob 98/nt/2000/xp e afins, postem. Pelo amor de deus!!!

Danilo Christiano


Responder

Gostei + 0

03/08/2004

Beppe

OFF: Não interessa se é usado Write ou cout <<, a API usada é WriteConsoleA ou WriteColsoleW.

Há uma flag na estrutura startupinfo que vc precisa setar também. Vc está usando pipes não? è preciso esperar até que haja algum resultado no seu buffer, senão a resposta é nula.


Responder

Gostei + 0

03/08/2004

Nildo

Christiano, seria muito problema pra você ser notificado a cada vez que fosse chamada o WriteConsoleA/W, e você poder ver os parametros que é passado para ele?


Responder

Gostei + 0

03/08/2004

Nildo

Ou melhor, você pode usar a função ReadConsole.


Responder

Gostei + 0

03/08/2004

Beppe

Ou melhor, você pode usar a função ReadConsole.

Não é assim tão fácil, porque o console do seu aplicativo não precisa ser necessariamente o mesmo do novo processo, além do que um processo GUI raramente terá um, de qualquer forma.


Responder

Gostei + 0

03/08/2004

Beppe

Danilo, segue o código que você estava procurando. Antes de tomar como solução, assegure-se que ele o retorna a 100¬ da saída em 100¬ dos casos. Digo isto porque já tive problemas no passado.

procedure TForm1.Button2Click(Sender: TObject);
const
  BufferSize = 4096;
var
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  Stdin, Stdout: record
      Rd, Wr: Cardinal;
    end;
  Data: TStringStream;
  Buffer: array[0..BufferSize - 1] of Byte;
  Bytes: Cardinal;
begin
  Data := TStringStream.Create(´´);
  try
    SA.nLength := SizeOf(SA);
    SA.lpSecurityDescriptor := nil;
    SA.bInheritHandle := True;

    // pipe que servirá como entrada para o novo processo
    Win32Check(CreatePipe(Stdout.Rd, Stdout.Wr, @SA, 0));
    DuplicateHandle(GetCurrentProcess, Stdout.Rd, GetCurrentProcess,
      @Stdout.Rd, 0, False, DUPLICATE_CLOSE_SOURCE or DUPLICATE_SAME_ACCESS);

    // pipe que servirá como saída para o novo processo
    Win32Check(CreatePipe(Stdin.Rd, Stdin.Wr, @SA, 0));
    DuplicateHandle(GetCurrentProcess, Stdin.Wr, GetCurrentProcess,
      @Stdin.Wr, 0, False, DUPLICATE_CLOSE_SOURCE or DUPLICATE_SAME_ACCESS);

    FillChar(SI, SizeOf(SI), 0);
    SI.cb := SizeOf(SI);
    SI.wShowWindow := SW_HIDE;
    SI.hStdInput := Stdin.Rd;
    SI.hStdOutput := Stdout.Wr;
    SI.hStdError := Stdout.Wr;
    SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
    Win32Check(CreateProcess(´C:\Arquivos de programas\Borland\Delphi5\Bin\dcc32.exe´, nil, nil, nil, True, 0, nil, nil, SI, PI));

    // espera que o processo-filho termine
    while WaitForSingleObject(PI.hProcess, 100) = WAIT_TIMEOUT do
      Application.ProcessMessages;

    Win32Check(CloseHandle(PI.hThread));
    Win32Check(CloseHandle(PI.hProcess));

    Win32Check(CloseHandle(Stdin.Rd));
    Win32Check(CloseHandle(Stdin.Wr));
    Win32Check(CloseHandle(Stdout.Wr));

    // lê a saída encontrada no fim de leitura da pipe do processo filho
    // até esgotar
    repeat
      if not ReadFile(Stdout.Rd, Buffer, SizeOf(Buffer), Bytes, nil) or (Bytes = 0) then Break;
      Data.Write(Buffer, Bytes);
    until False;
    Win32Check(CloseHandle(Stdout.Rd));

    Memo1.Lines.Text := Data.DataString;
  finally
    Data.Free;
  end;
end;


Bom proveito.


Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar