How to send a string via PostMessage?
Asked Answered
F

3

17

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.

Feller answered 24/8, 2009 at 23:14 Comment(0)
A
14

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;
}
Acuity answered 24/8, 2009 at 23:34 Comment(1)
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?Warring
E
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.

Expatriate answered 24/8, 2009 at 23:32 Comment(3)
OK, time to go home. I answered as if the OP was asking about SendMessage and the whole point was that is PostMessage...Expatriate
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.Acuity
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).Madonna
H
0

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.

Highboy answered 24/8, 2009 at 23:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.