Advertisement

Using streams with Windows

Started by February 18, 2003 11:22 AM
3 comments, last by Dawnstrider 21 years, 9 months ago
I posted a while back about having trouble with making iostream not wait for input so I could have my little text based game run in real time, and one thing that was suggested to me was to make a simple dialogue application instead. So I''ve been playing with that, and I''m fairly cofident that I can finish getting an interface with just two basic edit text boxes (one for input and output) working. But what occured to me while coding it was that I was -essentially- doing the same thing as iostream, just separating the input and output to two different windows. So I''m wondering if it might be possible to derive my own class from one of the iostream bases and make it work with two Windows edits. I figured I could make it similar to the iostream class, have the insertion operator print to the output window and the extraction operator get characters from the input window, and so on. Maybe have private members that stored the IDs of the edits, or even better create them itself and have their message processing be member functions of the class. Is this possible to do without it being far more trouble than its worth? Any hints as to how to start (like what class I would want to inherit from) would be great, too. Also, I''m curious about some of the behavior of iostream, and where it comes from. I noticed with the extraction operator, it seemed to only wait for user input if there was nothing in the stream, otherwise it grabbed characters until it hit a space and returned immediately. Is this accurate? And if so, is this waiting behavior defined by iostream, or is it defined at a higher level such as the streambuf class? Thanks in advance, Chris.
If you're really curious about how IOStream works, I recommend the book "Standard C++ IOStreams and Locales" by Langer & Kreft. There is much more to streams than can be discussed in the confines of a forum thread

Since edit boxes do not expose either a file descriptor or a stream , you'll have to interact with them through strings. The iostream library provides a stringstream class (<sstream> header) that lets you access the written/unread data as a std::string, but using it would still leave the task of moving that data to and from the edit control up to you.

The stream classes themselve mostly handle interaction with the data on a 'formatted' level. Moving the data to and from the device (here an edit box) is the task of the streambuffer (which are at a lower level). The 'waiting' behaviour ( more accurately named 'blocking' ) is defined by the device (file, keyboard, socket) itself. A read on a non-blocking device which holds no data would just be reported as a failure ( iostream::fail() becomes true ).

You will have to make the streambuffer write to the edit box 'buffer' on overflow ( when the stream buffer is full and you try to write more data ) and on flushes. The input behaviour seems a bit more complex. Either you need to have the editbox itself write to the stream buffer when data is entered ('push' model), which implies registering some sort of callback with the editbox itself (or hooks, or whatever...). Or you can have the stream buffer read from the edit box whenever an underflow occurs ( when you try to read from an empty stream buffer ). Which has the disadvantage that you will either have to remove that data from the edit box (technically, the stream buffer wouldn't even have to keep track of the data itself, just rely on the edit box to buffer it), or accept to get 'duplicated' data when you do multiple reads.

The starting point for you is to derive your own stream buffer.
The main functions you want to modify are underflow (which reads a character from the device when the buffer is empty), and overflow (which writes a character to the device when the buffer is full), maybe the related xsgetn, xsputn (which handle multiple characters at a time when possible - and otherwise call under/overflow multiple times), and possibly uflow.

Hope this helps.

Note: I realise this is not a 'For Beginner' answer, but non-blocking stream IO and writing custom streams buffers is not a 'For Beginner' question. I've only done it once (OpenGL/GLUT text output stream), and relied heavily on the aforementioned book.

Note: You could also try playing with the readsome stream buffer member function.

[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

[edited by - Fruny on February 18, 2003 12:56:14 PM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Advertisement
Thanks for the help, I think I''m mostly following you. So basically, iostream does the formatting of the text, and its associated streambuf object tells where the text is retrieved/put. So if I derived my own streambuf class, that could redirect where its put to an edit window, and then I could use the already existing iostream class with the new buffer. And I wouldn''t have to deal with redoing any of the functions or operators in iostream, they should work the same. Is that correct?

The one thing I don''t see, though, is where I can overload flush. I don''t see anything that sounds like that in the streambuf class. Am I just missing it, or do I need to do something different?

Oh, and one other thing. Since blocking is defined by the device, it probably wouldn''t come up with my own streambuf class, right?
You won''t have to write your own iostream class, unless you want to add stuff to its interface. For example fstreams offer things like open(), close() which are not part of the ''generic'' iostream interface.

So, all you need is to make a stream buffer, and set it as the buffer to be used by an iostream object ( iostream s; editboxstreambuffer buf; s.rdbuf( buf ); ).

You can also, for convenience, derive a stream class whose only difference is that it creates an editboxstreambuffer instead of a whateverstreambuffer

From memory, flush() calls either pubsync() or sync().

No, blocking shouldn''t happen with your stream buffer, unless you write it so it waits for a Win32 message indicating that data has been written to the edit box. If you make it nonblocking, be ready to handle input failure.

Either read the stringstream code (which ought to be non-blocking) in the header file, or get the book I mentioned. The error handling within the stream can get intricate (e.g. errors really are signaled by exceptions, raised by the stream buffer, and caught by the iostream object, which then converts them into a flag ... )


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
I''m slowly getting it working, I think. Thanks for all the help

This topic is closed to new replies.

Advertisement