Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
500 Users Online NOW
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi



Loremo - the 1.5 liter car coming in 2009




Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (5)


Capture Output of a Console Application - RevisedFormat this article printer-friendly!Bookmark function is only available for registered users!
Product:
Delphi all versions
Category:
System
Skill Level:
Scoring:
Last Update:
09/05/2002
Search Keys:
delphi delphi3000 article borland vcl code-snippet DOS Console Output CreateProcess CreatePipe PeekNamedPipe Redirection
Times Scored:
18
Visits:
9373
Uploader: Jochen Fromm
Company:
Reference: N/A
 
Question/Problem/Abstract:
How do you start a DOS or Console Application and
capture the output while it is running ? For example,
how do you capture the output of the FileCompare (FC)
Command ?
Answer:



There are already two articles about this problem,

http://www.delphi3000.com/articles/article_2112.asp
http://www.delphi3000.com/articles/article_2298.asp

but they get the output when the process is finished.
There are also two Microsoft Articles about Redirection of
DOS Applications :

Microsoft Knowledge Base Article - Q190351
HOWTO: Spawn Console Processes with Redirected Standard Handles
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q190351

Microsoft Knowledge Base Article - Q150956
INFO: Redirection Issues on Windows 95 MS-DOS Applications
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q150956

The basic idea is to start the console application with
CreateProcess and redirect the input and output with
pipes, enabling the calling process to access the output
of the console application.

It is important to capture the output while the process is
still running. If the output-pipe is blocked by an overflow,
new information can not be written from the console app to
the output-pipe, and the program stops. In this case we have
a classic deadlock situation: the user (parent process) is
waiting for the child-process to finish, and the child-process
is waiting for the user to clear the buffer.


procedure CaptureConsoleOutput(DosApp : string;AMemo : TMemo);
const
  ReadBuffer = 1048576;  // 1 MB Buffer
var
  Security            : TSecurityAttributes;
  ReadPipe,WritePipe  : THandle;
  start               : TStartUpInfo;
  ProcessInfo         : TProcessInformation;
  Buffer              : Pchar;
  TotalBytesRead,
  BytesRead           : DWORD;
  Apprunning,n,
  BytesLeftThisMessage,
  TotalBytesAvail : integer;
begin
  with Security do
  begin
    nlength              := SizeOf(TSecurityAttributes);
    binherithandle       := true;
    lpsecuritydescriptor := nil;
  end;

  if CreatePipe (ReadPipe, WritePipe, @Security, 0) then
  begin
    // Redirect In- and Output through STARTUPINFO structure

    Buffer  := AllocMem(ReadBuffer + 1);
    FillChar(Start,Sizeof(Start),#0);
    start.cb          := SizeOf(start);
    start.hStdOutput  := WritePipe;
    start.hStdInput   := ReadPipe;
    start.dwFlags     := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
    start.wShowWindow := SW_HIDE;

    // Create a Console Child Process with redirected input and output

    if CreateProcess(nil      ,PChar(DosApp),
                     @Security,@Security,
                     true     ,CREATE_NO_WINDOW or NORMAL_PRIORITY_CLASS,
                     nil      ,nil,
                     start    ,ProcessInfo) then
    begin
      n:=0;
      TotalBytesRead:=0;
      repeat
        // Increase counter to prevent an endless loop if the process is dead
        Inc(n,1);
        
        // wait for end of child process
        Apprunning := WaitForSingleObject(ProcessInfo.hProcess,100);
        Application.ProcessMessages;

        // it is important to read from time to time the output information
        // so that the pipe is not blocked by an overflow. New information
        // can be written from the console app to the pipe only if there is
        // enough buffer space.

        if not PeekNamedPipe(ReadPipe        ,@Buffer[TotalBytesRead],
                             ReadBuffer      ,@BytesRead,
                             @TotalBytesAvail,@BytesLeftThisMessage) then break
        else if BytesRead > 0 then
          ReadFile(ReadPipe,Buffer[TotalBytesRead],BytesRead,BytesRead,nil);
        TotalBytesRead:=TotalBytesRead+BytesRead;
      until (Apprunning <> WAIT_TIMEOUT) or (n > 150);

      Buffer[TotalBytesRead]:= #0;
      OemToChar(Buffer,Buffer);
      AMemo.Text := AMemo.text + StrPas(Buffer);
    end;
    FreeMem(Buffer);
    CloseHandle(ProcessInfo.hProcess);
    CloseHandle(ProcessInfo.hThread);
    CloseHandle(ReadPipe);
    CloseHandle(WritePipe);
  end;
end;






Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
how about TStartUpInfo.hStdError handle?
    Terrance Hui (Jun 12 2008 9:14AM)

I try it but found that did not capture the error result. After added the line below and now is work for me. anyway, that is a great tips.

  start.hStdError := WritePipe;

Respond

This is simply wrong.
    Peter Sumskas (Feb 4 2005 12:04AM)

In the example you have connected the pipe from stdinput to stdoutput.

What this means is that if the process writes to stdoutput and then reads from stdinput it will read back in what it just wrote out.

Further, how do you put any information into the process' standard input? You can't...that's what the write handle is for - but you've connected that to the output of std out.

Read the Win32 documentation of CreatePipe for details.

Respond

Not working propertly....
    Luis (Sep 5 2002 2:25PM)

I try to use it with dbbackup (from sybase) this backup utility does not change the line on every percentage instead it stays in the same line and override the previous one...

like:
(10450 of 10945 pages, 75% complete)  

on where that line change the page number and percentage but in the command line it stays in the same command line....

when I try to run your procedure it does not fires until the process finish (100%)...


Luis
Respond

RE: Not working propertly....
Jochen Fromm (Sep 5 2002 2:36PM)

In the case of applications/commands like FC it works fine. It guess this has something to do with the way the console application handles it's output. Maybe in your case you have to use the DuplicateHandle Function, like it is shown in the Microsoft article, because the console application allocates new buffers ?! But I'm not sure. Perhaps someone else has a bright idea :-)
Respond

RE: RE: Not working propertly....
Surasak Khamthong (Sep 9 2002 7:09AM)

test for sent somthin to delphi3000.com
Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
C.A. Longen
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)