4

Can a windows message box be display using the cout syntax?

I also need the command prompt window to be suppressed / hidden.

There are ways to call the messagebox function and display text through its usage, but the main constraint here is that cout syntax must be used.

cout <<  "message";

I was thinking of invoking the VB msgbox command in the cout output, but couldn't find anything that worked.

Any ideas?

CheeseConQueso
  • 5,831
  • 29
  • 93
  • 126
  • 3
    If you have a C++ console app, and you're trying to turn it into a Windows app, this is the least of your worries. – Daniel Pryden Nov 13 '09 at 16:49
  • 1
    How many dialog boxes would `cout << "Hello" << user_name;` display? – Éric Malenfant Nov 13 '09 at 18:23
  • @Dan - It was a request of an instructor at the school I work at who is teaching C++ but does not want students able to access the command promopt. @Eric - just 1 – CheeseConQueso Nov 13 '09 at 19:08
  • @Cheese: I would suggest having the students use a mix of messagebox (because it works) and stringstream (because it's a stream akin to cout) would be a better solution. See Stephen Newell's answer. Console programs and messagebox programs are rather different, and trying to force students to treat them similarly strikes me as a bad way to teach. – Brian Nov 13 '09 at 20:14
  • @Brian - I agree, but I'm not the teacher and not the person to tell the teacher how to run his class - he is the head of the dept – CheeseConQueso Nov 13 '09 at 20:33
  • This professor is being completely unreasonable, IMO. You could write a new class that wraps a `stringstream` that flushes to a `MessageBox`, but then you wouldn't be able to simply use `cout` unless you modify or replace the C++ runtime. But, this will be both surprising and confusing to the students in the class, and in the long run create more problems than it solves. If command-line access is really so much a concern, then use something like "Deep Freeze" and disconnect the system from the network. – greyfade Nov 13 '09 at 20:44
  • I'd point the instructor to this thread then and let him see why what he wants isn't going to work. A reasonable instructor will recognize that there are better solutions than what he precisely wanted. Jerry Coffin has a solution that would also allow MessageBox to be treated in an object-oriented manner (the instructor may like this). – Stephen Newell Nov 13 '09 at 20:44
  • thanks for all the info guys... I know its a weird request... I got it to the point where it would kill the cmd.exe and display a message in a message box, but I wasnt using cout - thats how this thread started. I'll let him know that it would be too much to try and trick the compiler into treating cout like msgbox – CheeseConQueso Nov 13 '09 at 22:03

7 Answers7

11

C++ streams work with console or file streams. Windows work on a more or less completely different paradigm, so the cout context isn't really a good one for working with this. You could probably completely mash up something that would end up more or less working, and looking more or less similar to this syntax, but it's not really worth it when you can just do:

MessageBox( NULL, message, "", MB_OK );

See the full docs on MessageBox for more info.

Russell Newquist
  • 2,656
  • 2
  • 16
  • 18
  • yeah that's what i suggested to this person, but they want cout to be part of the ordeal for some obscure reason – CheeseConQueso Nov 13 '09 at 17:05
  • They want cout specifically, or they want a stream similar to cout? – Bill Nov 13 '09 at 19:02
  • im 90% sure that they want cout specifically. it is an instructor and he is probably going to by the book. they don't want the students being able to access the command prompt – CheeseConQueso Nov 13 '09 at 19:19
  • 1
    Have him log in here so we can tell him IT IS NOT POSSIBLE using cout. – jmucchiello Nov 13 '09 at 20:42
  • @jmucchiello, don't go so fast if you are not positive and have a look here: http://stackoverflow.com/questions/1730427/display-message-in-windows-dialogue-box-using-cout-c/1734006#1734006 – Fernando N. Nov 14 '09 at 18:29
9

First thing you should take into account is that MessageBox stops the thread until you close the window. If that is the behavior you desire, go ahead.

You can create a custom streambuf and set it to std::cout:

#include <windows.h>
#include <sstream>
#include <iostream>

namespace {
    class mb_streambuf : public std::stringbuf {
        virtual ~mb_streambuf() { if (str().size() > 0) sync(); }
        virtual int sync() {
            MessageBoxA(0, str().c_str(), "", MB_OK);
            str("");
            return 0;
        }
    } mb_buf;

    struct static_initializer {
        static_initializer() { 
            std::cout.rdbuf(&mb_buf); 
        }
    } cout_buffer_switch;
}

int main()
{
    std::cout << "Hello \nworld!"; // Will show a popup
}

A popup will be shown whenever std::cout stream is flushed.

Fernando N.
  • 6,369
  • 4
  • 27
  • 30
  • the first thing it told me was to include stdafx.h.... after including that, I got bunch of errors that I don't have access to until that person is back to test some new things with me again – CheeseConQueso Nov 17 '09 at 20:40
  • Those problems don't have anything to do with this code but with "precompiled headers" options in your project. – Fernando N. Nov 22 '09 at 11:59
  • 1
    One note here: The following only shows one line per block of text between "endl"s. Unless I explicitly terminate the output withendl, or call cout.flush() the very last block isn't displayed. (e.g cout << "abc" << endl << "bah"; won't display "bah" without calling flush) Interestingly you can get a multiline display by passing "\r\n" as literal text. . . – Jason D Nov 25 '09 at 05:37
  • @Jason D. Right, it should have a overwritten destructor flushing remaining data before exit. By the way, `< – Fernando N. Nov 25 '09 at 20:33
  • got it to work... thanks... the problem wasn't in the code, it was the way the project was set up – CheeseConQueso Nov 25 '09 at 20:39
  • there is also a command to suppress the cmd.exe from showing .... i forgot where i found it, but it would help in here. also, if this whole thing could be made as a write-protected include file to be given to his students, that would be an epic win – CheeseConQueso Nov 25 '09 at 20:40
6

By including sstream, you can use std::ostringstream and build a message using the iostream library. You can then call .str().c_str() and get a char * to pass to MessageBox.

Stephen Newell
  • 7,330
  • 1
  • 24
  • 28
6

When confronted with this in the past, I've used a stringstream along with a manipulator that displays the current contents of the stringstream using MessageBox:

#include <windows.h>
#include <sstream>
#include <ostream>

std::ostream &MessageBox(std::ostream &s) {
    std::ostringstream *st = dynamic_cast<std::ostringstream *>(&s);
    if (NULL != st)
        ::MessageBox(NULL, st->str().c_str(), "", MB_OK);
    return s;
}

To use this, the syntax looks a fair amount like using cout, but with MessageBox replacing std::endl. For example:

std::ostringstream stm;
stm  << " blah blah blah. Value: " << 1213.1231 << MessageBox;

Edit: mostly for fnieto. In this case, the downcast really is necessary. The reason is fairly simple: a typical inserter receives and returns a reference to an ostream:

std::ostream &operator<<(std::ostream &os, T const &t) { 
    // code here to insert t into os, then return os;
}

This takes the original stringstream object and silently (and safely) casts it up to a simple ostream. That's fine in itself, and works fine for most inserters and manipulators, because they only interact with the ostream interface themselves.

This manipulator, however, is a bit different -- it uses the str() member, which ostream doesn't define at all. For our call to str() to resolve and compile, we have to convert the ostream & to an ostringstream &, so the compiler is aware that the object we're working with really will have a str() member.

To eliminate the downcast, we'd really only have one choice: make its parameter an ostringstream &. That would work as long as we never chained operators:

my_stream << x;
my_stream << MessageBox;

but trying to chain those would fail:

// should be equivalent:
my_stream << x << MessageBox;

Worse, the compiler's error message will probably try to tell the user something about std::basic_ostream<char>::str(), which isn't mentioned in the user's code at all. Worse still, most people are sufficiently accustomed to chaining or not giving identical results that it would probably take them a while to even figure out why the code sometimes worked fine, and other times failed to compile, with a completely indecipherable error message.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
3

No simple way anyway.

The c in cout stands for console, so you're probably out of luck.

If it's just the syntax you're looking to copy, then you could write your own stream class that creates a message box under the hood and displays it.

Glen
  • 21,816
  • 3
  • 61
  • 76
  • 3
    He only wants cout-like syntax, not cout itself. An std::ostringstream can be used to build the string to pass to the windows object. As per Stephen Newell's answer. – Clifford Nov 13 '09 at 18:14
  • @Clifford, yes, I understand he might only want the stream syntax. That's why I mentioned using his own stream class that calls the message box functionality under the hood. maybe I wasn't clear enough.... – Glen Nov 13 '09 at 20:12
  • In most OS you can redirect standard input/output to another file or pipe, and if that is done, then it is no longer 'console out', but just plain 'standard output' – David Rodríguez - dribeas Nov 16 '09 at 11:51
3

You may want to check this out: How can I redirect stdout to some visible display in a Windows Application?

Community
  • 1
  • 1
BostonLogan
  • 1,576
  • 10
  • 12
  • 1
    Using this technique combined with Jerry COffin's technique will probably yield a program which, without changes to anything but the initialization, successfully turns cout into a messagebox. Also, it will suck (but might make this person happy). – Brian Nov 13 '09 at 19:03
1

Can a windows message box be display using the cout syntax?

You can't do it with std::cout. std::cout doesn't even promise to handle Unicode/wide characters (see std::wcout), although Windows's cout has no trouble with wide characters.

You could easily do it with the same syntax; that is, you could easily write a library that overloads operator<< to display dialog boxes. Trying to pass all the information to the dialog box that way would be very difficult, though (how would you you say which buttons to show, what those buttons should do when pressed, where those buttons should be, and the size and position of the window itself?).

You may want to look at something like ncurses. The syntax is different, but I have a feeling it's what your coworker is looking for.

Max Lybbert
  • 19,717
  • 4
  • 46
  • 69