views:

1245

answers:

3

Inside my app, I want to send a message to a dialog from a different thread. I want to pass an std::exception derived class reference to the dialog.

Something like this:

try {
       //do stuff
}
catch (MyException& the_exception) {
 PostMessage(MyhWnd, CWM_SOME_ERROR, 0, 0); //send the_exception or the_exception.error_string() here
}

I want to receive the message in my dialog and show the error that is in the_exception.error_string()

LPARAM CMyDlg::SomeError(WPARAM, LPARAM)
{
    show_error( ?????
    return 0;
}

passing the std::string the_exception.error_string() using PostMessage would also be ok, I guess.

A: 

As long as you are within a process simply passing a void* pointer and some care on object lifetime are enough.

If is SendMessage you can pass it in LPARAM as a void* cast, and the client uncast it back to your string type. Because SendMessage is synchronous, you are safe:

If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message

If you want to use PostMessage then you'll have to do an explicit hand off because the call is asynchronous: make a copy of the string on the heap and by calling the PostMessage you have passed the delete responsability to the calee (the dialog).

If you go out of process (MyhWnd belongs to a different process) then is a whole different story and you'll have to marshal your message into something like a global atom.

Remus Rusanu
OK, time to go home. I answered as if the OP was asking about SendMessage and the whole point was that is PostMessage...
Remus Rusanu
Good to point out that SendMessage is synchronous and you don't have to worry about transfering ownership. However, SendMessage can be re-entrant, i.e., during the call to SendMessage your thread may be pumping messages, so you have to be careful the state that your passing to the other thread can't be mutated within any of your wndprocs.
Michael
IMO this is the correct answer: use SendMessage and copy the message in the receiving thread upon getting it. No need to set yourself up the bomb with complicated PostMessage/synchronisation issues for a simple string pass (a string that I presume will be rather short).
Roel
+3  A: 

You can't pass the address of the string in PostMessage, since the string is probably thread-local on the stack. By the time the other thread picks it up, it could have been destroyed.

Instead, you should create a new string or exception object via new and pass its address to the other thread (via the WPARAM or LPARAM parameter in PostMessage.) The other thread then owns the object and is responsible for destroying it.

Here is some sample code that shows how this could be done:

try
{
    //do stuff
}
catch (MyException& the_exception)
{
    PostMessage(MyhWnd, CWM_SOME_ERROR, 0, new string(the_exception.error_string));
}


LPARAM CMyDlg::SomeError(WPARAM, LPARAM lParam)
{
    // Put in shared_ptr so it is automatically destroyed.
    shared_ptr<string> msg = reinterpret_cast<string*>(lParam);

    // Do stuff with message

    return 0;
}
Michael
Hi, thanks a lot for your answer. you forgot the cast to LPARAM PostMessage(MyhWnd, CWM_SOME_ERROR, 0, reinterpret_cast<LPARAM>(new string(the_exception.error_string)) );And how about using auto_ptr instead:std::auto_ptr<string> msg(reinterpret_cast<string*>(lParam));Because this shows the transfer of ownership.
rec
ouch, bad formattingtesting line breaktesting line break
rec
A: 

As long as you know that your window (or instance of CMyDlg) will still be around after posting the message you could simply store the error string in a member variable and read from this in your message handler.

Alan