Fórum Redirecionar STDOUT de programas console #243908
21/07/2004
0
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
Curtir tópico
+ 0Posts
21/07/2004
Danilo Christiano
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
Gostei + 0
21/07/2004
Beppe
Gostei + 0
31/07/2004
Vinicius2k
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+
Gostei + 0
31/07/2004
Nildo
Gostei + 0
31/07/2004
Vinicius2k
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+
Gostei + 0
31/07/2004
Nildo
Gostei + 0
31/07/2004
Vinicius2k
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...
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+
Gostei + 0
02/08/2004
Danilo Christiano
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
Gostei + 0
03/08/2004
Beppe
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.
Gostei + 0
03/08/2004
Nildo
Gostei + 0
03/08/2004
Nildo
Gostei + 0
03/08/2004
Beppe
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.
Gostei + 0
03/08/2004
Beppe
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.
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)