Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Deriving your own stream from the iostreams framework

0.00/5 (No votes)
24 Jul 2002 2  
An exploration of extending the iostreams framework through custom streams.

Introduction

This is the third in my trilogy of articles on iostreams. Having covered how to create inserters, extractors and modifiers, it follows that I should explain how to write a stream. I am going to provide two classes, one of which overrides basic_streambuf, and provides the streaming implementation and one which derives from ostream in order to provide us with a stream to pass information to our underlying code.

The idea

The basic idea for this article came about because someone asked a question in the C++ forum, regarding redirecting printf to an edit box. So the task at hand will be to create a stream which appends the stream input to the text of an edit box.

MFC ?

The article code takes the form of an MFC dialog project, but the actual stream does not use MFC. You can copy the header file into any Win32 project, and it should work just as well. I suspect it should work for WTL as well, but I have not tested this at ALL, OK ?

Point of entry

Because we are deriving from an iostream class, we need to override specific functions in order for our code to integrate into the library. We have three options. A stream operation can look something like this:

cout << "this is some text " << 42 << InstanceOfSomeOtherType;

In this example, the possible places for cout to handle the input are as follows:

FunctionWhere called
overflowGets called once for each character passed into the stream
flushgets called when a flush occurs, usually via endl or a destructor
xsputnGets called once per shift operator

So we see we have three options.

  1. pass each character into the edit box when overflow is called
  2. store each character when overflow is called and pass it in one go in flush
  3. pass each string or other object one at a time in xsputn

Option 1 should be used only by streams with low overhead in performing their functionality. Option 2 is best for costly operations. Option 3 is about as easy as option 1, and more efficient. We will pursue option 3.

The stream

Basically our approach inside our function is to call GetWindowTextLength to get the length of the text in the window, and GetWindowText to get the string, then we concatenate it with the one we already have, and use (surprise) SetWindowText to put it back in.

In order to do all this, we need the HWND of the edit box, so we provide a function in both stream objects that takes a HWND and returns the one previously stored. If it has not been set, our stream does nothing.

The code looks like this:

        std::streamsize xsputn(const charT * pChar, std::streamsize n)
        {
            if (NULL != m_hWnd)
            {
                const int nLength = ::GetWindowTextLength(m_hWnd) + 1;
                char * pText = new char [nLength];
                ::memset(pText, 0, nLength);
                ::GetWindowText(m_hWnd, pText, nLength);

                std::string s(pText);
                delete [] pText;

                s += std::string(pChar);

                ::SetWindowText(m_hWnd, s.c_str());

                return static_cast<std::streamsize>(s.length());
            }
            else
                return 0;
        }

Now we just need to initialise our stream with the HWND of the edit box, and call our stream with the text we want to pass in. The demo program provides a disabled edit box that shows the text already received, and an enabled one, whose contents is streamed in when you press the button provided.

If you're the person I wrote this for, I hope it helps you. Either way, I hope it provides you with some more ideas as to ways that iostreams can be used to make your life easier with regard to input and output. It is an awesome library in my opinion, and one that seems to me to be under utilised by a lot of people. I hope you find it useful to you.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here