How to send a string via PostMessage?

21,177

Solution 1

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 (const MyException& the_exception)
{
    PostMessage(myhWnd, CWM_SOME_ERROR, 0, new std::string(the_exception.error_string));
}


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

    // Do stuff with message

    return 0;
}

Solution 2

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.

Share:
21,177
rec
Author by

rec

Hi Tony! hehe!

Updated on March 27, 2021

Comments

  • rec
    rec about 3 years

    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.

  • Michael
    Michael over 14 years
    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.
  • Roel
    Roel over 14 years
    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).
  • Serge Roussak
    Serge Roussak over 2 years
    There is a potential risk of the memory leakage here. For example, the PostMessage can be resulted with error because of the messages queue is full. Or, the target window may be already destroyed (so, the delete operator will not be called). May you suggest variants, how we can be safe against the memory leakage?