Board index » delphi » How to read pipe without buffering ?

How to read pipe without buffering ?

Hello,

I want create an application doing the same as a Dos Box with Delphi
Step 1 - Initialisation
  Create Pipes StdIn, StdOut & StdErr
    >CreatePipe(mStreamInput_r,  mStreamInput_w,  @mSecurity, 0)
    >...
  Create a process with pipes and executing a hidden cmd.exe
    >  with mStartupInfo do
    >    begin
    >      CB          := SizeOf(mStartupInfo);
    >      dwFlags     := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
    >      hStdInput   := mStreamInput_r;
    >      hStdOutput  := mStreamOutput_w;
    >      hStdError   := mStreamError_w;
    >      wShowWindow := SW_HIDE;
    >    end;
    >...
    >  l_ProcessStatus := CreateProcess(
    >    nil,                    // pointer to name of executable module
    >    PChar('cmd.exe'),       // pointer to command line string
    >    @mSecurity,             // pointer to process security
attributes
    >    @mSecurity,             // pointer to thread security
attributes
    >    True,                   // handle inheritance flag
    >    CREATE_SUSPENDED,    // creation flags
    >    mpEnvVar,               // pointer to new environment block
    >    PChar(mCurShellPath),   // pointer to current directory name
    >    mStartupInfo,           // pointer to STARTUPINFO
    >    mProcessInfo            // pointer to PROCESS_INFORMATION
    >  );
    Create a Process to Read The StdOut and
           one for StdErr (same process except for the pipe)
    like this
    >  Repeat
    >    FillChar(l_Buffer, SizeOf(l_Buffer), 0);
    >    ReadFile(i_Pipe,l_Buffer[0],C_BufferSizeRead-
1,l_BytesRead,nil);
    >    result := (l_BytesRead <> 0);
    >    if Result then
    >      o_Result := o_Result + l_Buffer;
    >  Until (l_BytesRead < C_BufferSizeRead-1) or (not Result)

Step 2 Execute a console application
  when a execute a [DIR.*.*] or a [cd ..] commands everything is OK
  BUT
  1) I have create an application that write to the stdout every second
the time
     and I receive not each message separately but all by 128 bytes
  2) When I try to execute Python I don't receive the welcome message
of the interpreter
     neither other message except some error messages (StdErr)

QUESTIONS
 - How to read a pipe byte by byte and not by 128 bytes ?  Just when a
byte is available !
 - Any idea why I cannot execute Python in my Shell, to get the same
result as in a Dos Box ?

Thanks,

Jacobo Belbo

Sent via Deja.com
http://www.deja.com/

 

Re:How to read pipe without buffering ?


AFAICS you are using exactly the same structure as I do, and I can't see
what's wrong with your code.

j_be...@hotmail.com schrieb:

Quote
>     Create a Process to Read The StdOut and
>            one for StdErr (same process except for the pipe)
>     like this

Guess with Process you mean a thread, don't you?

Quote
>     >  Repeat
>     >    FillChar(l_Buffer, SizeOf(l_Buffer), 0);
>     >    ReadFile(i_Pipe,l_Buffer[0],C_BufferSizeRead-
> 1,l_BytesRead,nil);
>     >    result := (l_BytesRead <> 0);
>     >    if Result then
>     >      o_Result := o_Result + l_Buffer;
>     >  Until (l_BytesRead < C_BufferSizeRead-1) or (not Result)

Here is the reader thread code I use, but IMHO there is no real
difference:

procedure TReaderThread.Execute;
begin
  while ReadFile(FPipe, FBuffer^, BufSize, FBytesRead, nil)
  and (FBytesRead > 0) do begin
    Synchronize(DoCallback);
    // fr W9x:
    if Terminated and (FBytesRead < BufSize) then exit;
  end;
end;

Quote
> Step 2 Execute a console application
>   when a execute a [DIR.*.*] or a [cd ..] commands everything is OK
>   BUT
>   1) I have create an application that write to the stdout every second
> the time
>      and I receive not each message separately but all by 128 bytes

What do you mean with 'message' here? Returning from ReadFile? Insert a
Beep there to have a response.

Are you sure your test application works well?

Run cmd.exe without hiding and without redirecting StdIn. Focus the
window and type. Can you receive the echo?

Quote
>   2) When I try to execute Python I don't receive the welcome message
> of the interpreter
>      neither other message except some error messages (StdErr)

I don't know Python, but does this really output to StdOut? Can you
redirect its output to a file?

-Michael

Re:How to read pipe without buffering ?


On Thu, 28 Dec 2000 19:10:18 GMT, j_be...@hotmail.com

Quote
<j_be...@hotmail.com> wrote:
>I want create an application doing the same as a Dos Box with Delphi
>Step 1 - Initialisation
>Step 2 Execute a console application
>  when a execute a [DIR.*.*] or a [cd ..] commands everything is OK
>  BUT
>  1) I have create an application that write to the stdout every second
>the time
>     and I receive not each message separately but all by 128 bytes
>  2) When I try to execute Python I don't receive the welcome message
>of the interpreter
>     neither other message except some error messages (StdErr)

>QUESTIONS
> - How to read a pipe byte by byte and not by 128 bytes ?  Just when a
>byte is available !

It's not anything you're doing.  When a Delphi console program notices
that its output isn't a character device, it buffers the output in
chunks of 128 bytes for better efficiency.  You're getting 128-byte
chunks because that's what the program is sending you.

You can modify the program (with some pain) so it won't do that.  I
don't think you can control it without modifying the program.

In some other cases you have better options.  For instance, if the
console program happens to be compiled in Microsoft C (or C++), there's
a trick to get it to use unbuffered output when writing to a pipe.  I
have some sample code at <http://www.subnormal.com/download/proctest.zip>.

Quote
> - Any idea why I cannot execute Python in my Shell, to get the same
>result as in a Dos Box ?

The Python release I have appears to be compiled with MSC.  Try the
sample code mentioned above.

--
Expect the unexpected.  And whenever possible, BE the unexpected.

Re:How to read pipe without buffering ?


Hello Michael,
Thanks for your help

1) About the problem 128 bytes packet it's a Dephi Feature
The better is to write a specific writeln like this
procedure WritelnDirect(const i_Str: String);
var l_StdOut : THandle;
    l_String : String;
    l_DW     : DWord;
begin
  l_StdOut := GetStdHandle(STD_OUTPUT_HANDLE);
  l_String := i_Str + #13#10;
  WriteFile(l_StdOut, l_String[1], Length(l_String), l_DW, nil);
end;

2) About Python : no problem to write to StdOut/StdErr
Just top known that it's a wonderfull scriptiong language OO
Free + open source + multi-platform : see www.python.org
But for this I don't have a final solution :-(

Jacobo

Sent via Deja.com
http://www.deja.com/

Re:How to read pipe without buffering ?


Hello David,
Thanks for your help :-)

1) About the writeln problem : I have found the solution
procedure WritelnDirect(const i_Str: String);
var l_StdOut : THandle;
    l_String : String;
    l_DW     : DWord;
begin
  l_StdOut := GetStdHandle(STD_OUTPUT_HANDLE);
  l_String := i_Str + #13#10;
  WriteFile(l_StdOut, l_String[1], Length(l_String), l_DW, nil);
end
Just one question pending, is it necessary to close the StdOut handle ?

2) About your code : proctest.zip
Wonderfull I receive at least the Welcome Message from Python
But how to send command to Python at the prompt message ?

Again thanks,

Jacobo Belbo

Sent via Deja.com
http://www.deja.com/

Re:How to read pipe without buffering ?


On Sat, 30 Dec 2000 16:09:41 GMT, j_be...@hotmail.com

Quote
<j_be...@hotmail.com> wrote:
>Hello David,
>Thanks for your help :-)

>1) About the writeln problem : I have found the solution
>procedure WritelnDirect(const i_Str: String);
>var l_StdOut : THandle;
>    l_String : String;
>    l_DW     : DWord;
>begin
>  l_StdOut := GetStdHandle(STD_OUTPUT_HANDLE);
>  l_String := i_Str + #13#10;
>  WriteFile(l_StdOut, l_String[1], Length(l_String), l_DW, nil);
>end
>Just one question pending, is it necessary to close the StdOut handle ?

No, just leave it open.  It'll be cleaned up when the program exits.

Quote
>2) About your code : proctest.zip
>Wonderfull I receive at least the Welcome Message from Python
>But how to send command to Python at the prompt message ?

I didn't deal with that part.  The way that code is organized it would
take another thread to do it.  You might want to just take the code that
deals with the OsFileInfo structure and add it to your own program.

--
"I don't want you to think I'm not incoherent." -- Harold Ross

Other Threads