Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2011-12

Re: How to poll for a byte in Input?

4 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

tcoq

Chad,
Thank you very much. I will try your approach, as I'm interested in the piping.

I also did some experimenting with SetConsoleMode, and also with SetFileAttributes, and with ReadFileEx. But no answer there. Still blocks.

Best regards,
Thierry

----- Mail Original -----
De: "Chad Berchek"
À: "FPC-Pascal users discussions"
Envoyé: Samedi 10 Décembre 2011 04h37:51 GMT +01:00 Amsterdam / Berlin / Berne / Rome / Stockholm / Vienne Objet: Re: [fpc-pascal] How to poll for a byte in Input?

tcoq wrote
Hello, I'm trying to poll the input stream to see whether there is a new character available, without blocking my software.

Maybe TInputPipeStream.NumBytesAvailable can help. You can find it in the documentation of the Pipes unit.

I tried an experiment to make sure it would work. I included the code for the experiment below. It works when stdin is from another process. It does not seem to work if stdin is from the console and I'm not sure why. I tried adding the Windows API call SetConsoleMode(StdInputHandle,
1) to disable line-input mode but it didn't seem to make any difference.

Regarding WaitForSingleObject, there are some comments on the MSDN documentation page regarding the use of this function for console input. In particular, one observation was that if the console is in line-input mode, WaitForSingleObject can return but ReadConsole will still block until a carriage return is entered. Perhaps the same is true for ReadFile. I have not tested this. See:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx

Code for the test: There are two programs. You can run WriteToPipe to see writing to the stdin stream of one process from another process. You can also test piped input using TestPipes by typing a command like:

type TestPipes.pas | TestPipes

However this does not seem to work:

TestPipes < TestPipes.pas

I don't know why exactly it doesn't appear to work with redirected input from a file or from the console. By the way, I'm using Windows XP Pro 64-bit. Here is the test code.

----- WriteToPipe.pas -----

program WriteToPipe;
{$MODE ObjFpc}

uses
SysUtils,
Process,

   Windows;
var
   AProc: TProcess;
   AString: string;
   ACount: Integer;
begin
   WriteLn('This will take about 20 seconds.');
   AProc := TProcess.Create(nil);
   try
     AProc.CommandLine := 'TestPipes.exe';
     AProc.Options := [poUsePipes];
     AProc.Execute;
     try
       for ACount := 0 to 5 do
       begin
         AString := IntToStr(ACount);
         AProc.Input.WriteBuffer(AString[1], Length(AString));
         Sleep (3000);
       end;
     finally
       AProc.Terminate(0);
     end;
   finally
     AProc.Free;
   end;
end.

----- End -----

----- TestPipes.pas -----

program TestPipes;
{$MODE ObjFpc}

uses
Classes,
Pipes,
SysUtils,

   Windows;
var
   AStream: TInputPipeStream;
   AString: string;
   AFile: TextFile;
begin
   Assign(AFile, 'output.txt');
   Rewrite(AFile);
   try
     AStream := TInputPipeStream.Create(StdInputHandle);
     while True do
     begin
       if AStream.NumBytesAvailable > 0 then
       begin
         SetLength(AString, AStream.NumBytesAvailable);
         AStream.ReadBuffer(AString[1], Length(AString));
         WriteLn(AFile, 'I just got this: ', AString);
       end else
       begin
         WriteLn(AFile, 'Waiting...');
         Sleep(1000);
       end;
     end;
   finally
     Close(AFile);
   end;
end.

----- End -----

Reply by email

Martin Schreiber
to tcoq
tcoq wrote 5 lines
Chad, Thank you very much. I will try your approach, as I'm interested in the piping. I also did some experimenting with SetConsoleMode, and also with SetFileAttributes, and with ReadFileEx. But no answer there. Still blocks.

IIRC non blocking pipes are difficult on Windows. MSEgui uses a separate thread in tpipereader for simulating non blocking pipes on Windows. http://gitorious.org/mseide-msegui
http://gitorious.org/mseide-msegui/mseide-msegui/blobs/master/lib/common/kernel/msepipestream.pas

Asynchronous IO on Windows is done by adding FILE_FLAG_OVERLAPPED to createfile() parameters and a toverlapped with an event object in readfile().
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=VS.85%29.aspx getoverlappedresult() can then be called with toverlapped or waitforsingleobject() with toverlapped.event as parameter. http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx

Don't forget to create and free the event object!
An example with FILE_FLAG_OVERLAPPED is here
http://gitorious.org/mseide-msegui/mseide-msegui/blobs/master/lib/common/serialcomm/msecommport.pas

All IIRC! ;-)

Martin

Reply by email

tcoq
to Martin Schreiber

thank you Martin,
I obviously failed somewhere. I did try FILE_FLAG_OVERLAPPED and everything attached to it, but the input is already opened, so i get an error. I'll try somewhat later when real life gives me a new break. Off for now.
Thierry
----- Mail Original -----
De: "Martin Schreiber"
À:
Envoyé: Samedi 10 Décembre 2011 18h50:09 GMT +01:00 Amsterdam / Berlin / Berne / Rome / Stockholm / Vienne Objet: Re: [fpc-pascal] How to poll for a byte in Input?

tcoq wrote 5 lines
Chad, Thank you very much. I will try your approach, as I'm interested in the piping. I also did some experimenting with SetConsoleMode, and also with SetFileAttributes, and with ReadFileEx. But no answer there. Still blocks.

IIRC non blocking pipes are difficult on Windows. MSEgui uses a separate thread in tpipereader for simulating non blocking pipes on Windows. http://gitorious.org/mseide-msegui
http://gitorious.org/mseide-msegui/mseide-msegui/blobs/master/lib/common/kernel/msepipestream.pas

Asynchronous IO on Windows is done by adding FILE_FLAG_OVERLAPPED to createfile() parameters and a toverlapped with an event object in readfile().
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=VS.85%29.aspx getoverlappedresult() can then be called with toverlapped or waitforsingleobject() with toverlapped.event as parameter. http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx

Don't forget to create and free the event object!
An example with FILE_FLAG_OVERLAPPED is here
http://gitorious.org/mseide-msegui/mseide-msegui/blobs/master/lib/common/serialcomm/msecommport.pas

All IIRC! ;-)

Martin

Reply by email

Martin Schreiber
to tcoq
tcoq wrote
I obviously failed somewhere. I did try FILE_FLAG_OVERLAPPED and everything attached to it, but the input is already opened, so i get an error.

IIRC I experienced the same with pipes on windows. So I used threads which works on win95+.

Martin

Reply by email