1

In a Delphi 7 console application, how can I check whether stdin holds a character, without blocking until one is entered?

My plan is that this console program will be executed by a GUI program, and its stdin will be written to by the GUI program.

So I want my console app to periodically check stdin, but I can't find a way of doing this without blocking.

I have looked at this answer, which gets me a stream pointing to stdin, but there's still no way to "peek" as far as I can see.

Community
  • 1
  • 1
Blorgbeard
  • 101,031
  • 48
  • 228
  • 272

4 Answers4

4

I think you have already found the right way to read stdin. It is meant to block when there's nothing more to be read.

The standard way to handle this is to use a separate thread to handle the pipe. When it receives new data from stdin it signals this to the processing thread, for example with a message passing mechanism.

Having said all that, if you really want to poll you can call PeekNamedPipe to check if there is data in the pipe.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
1

You could as the other answer says use threads, but even then you might have problems (using the threading method) unless you also investigate overlapped IO.

I normally use overlapped IO with serial ports rather than stdin, where "read a character if one is ready" is commonly needed, and where non-blocking IO is a usual way of working. You should be able to adapt the technique shown here. However, if I was writing an application that was keyboard driven (instead of purely driven by say, a file redirected to standard input) I would let go of StdIN, and use a CRT type unit. So, if you don't mind letting go of StdIn, and simply want to have a keyboard-driven input model, you could look at console based APIs and abandon the very limiting StdIn capabilities. For an example of a "kbhit" function that uses the Win32 Console APIs see here.

Community
  • 1
  • 1
Warren P
  • 65,725
  • 40
  • 181
  • 316
  • Overlapped I/O sounds interesting, thanks. The program's not keyboard driven, stdin will be piped from another program. – Blorgbeard Jun 03 '11 at 09:06
1

There is no other way (as far as i know), as reading from a pipe inside a separate thread. Otherwise as you already have seen, the readfile operation will block. I wrote an example how to do this, an example project is also available: redirect stdoutput

Edit: Well, reading your question another time, i understand that your problem lies within the console program, not the calling application. I wonder what your console application expects, normally a console application knows when it needs input and cannot proceede until the user enters this information. Do you need to check for an exit?

martinstoeckli
  • 23,430
  • 6
  • 56
  • 87
  • This console application is not intended to be used interactively. Perhaps I am trying to use stdin/stdout in a way which it is not intended to be used. I just need a way for the app that executed the console app to signal to it that it should abort. Normally I would WM_CLOSE the main window, but it's a console app. – Blorgbeard Jun 03 '11 at 09:03
  • @Blorgbeard - That's why i asked for the exit. Have a look at the example, it terminates the process when a timeout is reached, the same you can do when a user interactively wants to stop the application. – martinstoeckli Jun 03 '11 at 09:51
  • TerminateProcess doesn't give the program a chance to exit cleanly though? I want to try to signal it rather than just kill it (the example code is helpful though, thanks) – Blorgbeard Jun 03 '11 at 11:00
  • @Blorgbeard - I never used this myself, but maybe you should have a look at microsofts recommendation: http://msdn.microsoft.com/en-us/library/ms686722%28v=VS.85%29.aspx (see end of article). – martinstoeckli Jun 03 '11 at 11:49
  • That looks good, except the console app does not have a message loop to receive the broadcast. I managed to get PeekNamedPipe to work, as per David's answer. Thanks for the suggestions though :) – Blorgbeard Jun 03 '11 at 12:22
0

For a Stream if you .Read() the function result is the number of bytes read which will be zero if there was nothing there even if you asked for more. From the Delphi help for Classes.TStream.Read:

Read is used in cases where the number of bytes to read from the stream is not necessarily fixed. It attempts to read up to Count bytes into buffer and returns the number of bytes actually read.

Brian
  • 6,717
  • 2
  • 23
  • 31