2

Actually I have two questions:

  1. Is it safe to call SendMessage from a worker thread?
  2. Do CWnd methods, like MessageBox, call API function SendMessage behind the scene?

Per my understanding, when the worker thread calls SendMessage, it pushes the message into the message queue of the UI thread, and waits until this message is processed. In that case, it would be safe to do so.

I'm not quite sure about this. please correct me if I was wrong.

Thanks a lot.

------------------------ update ----------------------------------

As a conclusion:

  • It's safe to call the windows API ::SendMessage and ::PostMessage across threads.
  • It's not safe to call CWnd methods across threads. Some of the methods may be safe, but it's not guaranteed.

Great thanks to everyone.

Ken Zhang
  • 1,454
  • 2
  • 13
  • 27
  • 3
    It should also be noted that passing `CWnd` pointers between threads is dangerous because [they are stored in a per thread map](https://stackoverflow.com/a/45235803/7571258). – zett42 Jan 22 '18 at 17:12

2 Answers2

5

Is it safe to call SendMessage from a worker thread?

Yes. The system makes sure, that message handling is serialized on the receiving thread. When sending messages across threads, the sender is blocked until the message has been handled. The receiver only handles a cross-thread sent message when it executes message retrieval code (GetMessage, PeekMessage, etc.). Sent messages are never queued in the message queue. The documentation for SendMessage has additional details.

Do CWnd methods, like MessageBox, call API function SendMessage behind the scene?

Yes. For one, the message box will receive standard window messages like WM_CREATE or WM_NCCREATE as part of the dialog construction. Also, for owned windows (like modal dialogs), the system will send WM_ACTIVATE messages to both the window being deactivated, and the window being activated. I'm not sure why this matters, though, or why you asked this question in particular.

Now the question in your title:

Is it safe to call CWnd methods from another thread?

In general, no. It does depend on the member, though. Some are safe to call, others aren't. In particular, all methods that modify window state (contents, visibility, activation, etc.) should only be called from the thread that created the window. In case the call is not safe, the system will still be in a consistent state. However, your application may not be.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • Thank you very much for the answer. Actually, I'm trying to update the progress information to UI from a worker thread. I'm wondering if it's safe to call `CWnd::SetWindowText` directly on the window. Since `SendMessage` is thread-safe, If `CWnd::SetWindowText` calls `SendMessage`, then I think it would be also safe to call `CWnd::SetWindowText` directly. Is that right? – Ken Zhang Jan 23 '18 at 07:52
  • Probably yes, but It depends. as IInspectable said. But before SendMessage I would always check the CWnd with GetSafeHwnd(). Since SendMessage throw an `AfxThrowInvalidArgException` if `m_hWnd` not valid. – Tom Tom Jan 23 '18 at 12:20
  • 1
    @KenZhang It would be very bad design as a worker thread should not be concerned about UI but merely notify the UI thread about progress. This should be done via `PostMessage()` with a `WM_APP+x` message ID to decouple the threads. `SendMessage()` can easily deadlock if you are not careful (e. g. if you call it while the UI thread is waiting on the thread using `WaitForSingleObject()` or similar API). Also you don't want the worker thread to idle while the UI is updating (which can be time consuming), another good reason for `PostMessage()`. – zett42 Jan 23 '18 at 13:12
1

The ONLY way for a thread to access the UI is by using SendMessage or PostMessage.

Consider a machine with one core, where context switching occurs and you make direct access to the UI from a worker thread, you are potentially corrupting the UI thread registers !

Basically every UI framework offers a mechanism (many times several), for making UI changes from a thread. For instance Android offers an ASyncTask and a Handler.

RonTLV
  • 2,376
  • 2
  • 24
  • 38