Click here to Skip to main content
12,998,892 members (30,492 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


1 bookmarked
Posted 21 Oct 2010

Formatted MessageBox/AfxMessageBox

, 21 Oct 2010
Rate this:
Please Sign up or sign in to vote.
printf is so 1980s. If you don't want to dig out your shoulder pads and big hair why not go for a more modern C++ approach?Instead of a function try a stream buffer:class message_box_stream_buf : public std::basic_streambuf{ public: message_box_stream_buf( const...
printf is so 1980s. If you don't want to dig out your shoulder pads and big hair why not go for a more modern C++ approach?

Instead of a function try a stream buffer:

class message_box_stream_buf : public std::basic_streambuf<char>
        message_box_stream_buf( const std::string &caption )
            : buffer_( 513 ), caption_( caption )
            setp( &buffer_[ 0 ], &buffer_[ 512 ] );
        traits_type::int_type overflow( traits_type::int_type to_write )
            return sputc( traits_type::char_type( to_write ) );
        traits_type::int_type sync()
            if( pptr() != pbase() )
                MessageBoxA( NULL, &buffer_[ 0 ], caption_.c_str(), MB_OK );
                std::fill( buffer_.begin(), buffer_.end(), 0 );
                setp( &buffer_[ 0 ], &buffer_[ 0 ] + 512 );
            return traits_type::not_eof( ' ' );
        std::vector<char> buffer_;
        const std::string caption_;

I won't go into any detail as to how this lot works, if you want to know I'd suggest reading chapter 3 of "Standard C++ IOStreams and Locales" by Kreft and Langer.

To use it you need to plug it into an ostream:

    message_box_stream_buf sb( "Test App" );
std::ostream message_box_stream( &sb );

and once you do that it's just like using std::cout:

message_box_stream << "Hello Cruel World!" << std::endl;

which means you don't have to mess about with things like variable parameter lists and risk making a mistake that'll crash your program. No mucking about with format strings and making sure they match the order of your arguments either.

In fact you can ever rewire std::cout to use one of these stream buffers and lob all it's output to a message box:

message_box_stream_buf sb( "Test App" );
std::cout.rdbuf( &sb );
std::cout << "This is an output test. Have an integer: "
          << 87 << std::endl;

While this isn't too handy for cout it can be really handy for cerr.

Finally you get all the other goodness that comes with using iostreams. As well as being able to use them in C++ algorithms (via stream and streambuf iterators) they can handle types your write:

class vector3
		vector3( int x, int y, int z ) : x_( x ), y_( y ), z_( z ) {}
		friend std::ostream &operator<<(
                     std::ostream &str, const vector3 &to_display )
			return str << "x=" << to_display.x_
                                   << " y=" << to_display.y_
                                   << " z=" << to_display.z_;
		int x_, y_, z_;

a bit of object creation and voila, vector3s can be output to a message box:

message_box_stream_buf sb( "Test App" );
std::ostream message_box_stream( &sb );
    message_box_str << vector3( 1, 2, 3 ) << std::endl;

A couple of final points. The implementation above will only work for narrow characters. It's trivial to templatise it or convert it to use wide characters. Secondly the only OS specific bit is the call to MessageBoxA. That's asking to be parameterised as well. In fact if you use boost you'll see that there are several streambuffer classes in there that already do this sort of thing - all you have to do is adapt MessageBox to the signature the boost stream buffers expect and the job's done. I only didn't do that because I've not got boost installed on the system I'm writing this on!

So in conclusion: Don't fanny about with unsafe C idioms from years ago. You've got a C++ compiler and library, embrace it and use it. And as you do that look out for other abstractions that you can pull out and use elsewhere.



PS: Response to Ajay's comment below...

Writes to a stream are sent to the output device when one of two things happen: It runs out of buffer space OR you explicitly flush it. So you can pile up text to be output either in the same statement:

message_box_stream << " First bit " << " Second bit ";

or in different statements:

message_box_stream << " First bit ";
message_box_stream << " Second bit";

and nothing will be displayed (Depending on what you've already buffered.) When you flush the stream (std::endl flushes) it'll all come flooding out:

message_box_stream << "Hello";
message_box_stream << " Cruel ";
message_box_stream << " World!!";
message_box_stream << std::flush; // MessageBoxA called

It's no different to the way a stream to the console or writing to a file works - nothing comes out until it's flushed.

As to the comment that it's extraneous I'd suggest that you wouldn't create a new stream and stream buffer everytime you wanted to do some output, anymore than you'd open a console window. While I wouldn't advocate a global (like std::cout is) there's generally no problem with parameterising from above and passing a reference to the stream with a function call. This has the added bonus of allowing different levels of the program to compose things like error messages and only the top level pulls the trigger to do the display.

Another option, even though it's a global in disguise, is to make an instance part of an MFC application object and provide a simple wrapper around it to make it easier to use. To me:

application_message_box() << "It's all gone wrong! " << e.what() << std::endl;

is safer than any solution involving printf style functions as whatever disasters I inflict on the formatting it's unlikely to crash the process. However your milage may (and probably will) vary!


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer (Senior)
United Kingdom United Kingdom
I've been programming since 1985 - starting with Fortran 77, then moving onto assembler, C and C++ in about 1991. I also know enough Java and Python to read code but you probably wouldn't want me writing it.

I've worked in a wide variety of application areas - defense, banking, games and security with the longest stints being in security. I also seem to end up programming devices far too often. This time I'm programming terahertz band body scanners.

You may also be interested in...

Comments and Discussions

Generalnot bad,some times i will use messagebox to test my project.... Pin
fronz@sohu.com18-Jan-12 0:00
memberfronz@sohu.com18-Jan-12 0:00 
GeneralReason for my vote of 5 5. always. Pin
Niklas Lindquist16-Jan-11 22:14
memberNiklas Lindquist16-Jan-11 22:14 
GeneralAnd Bad Bad Bad design is when you advocate using variable a... Pin
Aescleal23-Oct-10 10:45
memberAescleal23-Oct-10 10:45 
GeneralAnd seriously, from my perspertive, streaming, buffering and... Pin
Ajay Vijayvargiya23-Oct-10 9:05
memberAjay Vijayvargiya23-Oct-10 9:05 
GeneralI just read the added stuff. My point was *just* to avoid fo... Pin
Ajay Vijayvargiya23-Oct-10 8:59
memberAjay Vijayvargiya23-Oct-10 8:59 
I just read the added stuff. My point was *just* to avoid formatting calls, if any, and use the MessageBoxFormatted directly, and nothing else. In MFC, CString is there, the + operators are there, even the stringstream (don't know exact classname) is there where << operator may be used for any datatype (where CString wouldn't work). Why do you need this extra stuff just for a messagebox??
For readers, this is truly an alternate, but not for me! Smile | :)
GeneralQuite good, and powerful. But not adaptable easily. My point... Pin
Ajay Vijayvargiya21-Oct-10 2:56
memberAjay Vijayvargiya21-Oct-10 2:56 
GeneralReason for my vote of 5 Wonderful: an elegant and powerful s... Pin
Sauro Viti21-Oct-10 2:25
memberSauro Viti21-Oct-10 2:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170622.1 | Last Updated 22 Oct 2010
Article Copyright 2010 by Aescleal
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid