Reputation: 621
I know that in order to access the UI controls from another thread, I should use PostMessage()
. However, PostMessage()
is asynchronous, so for example if I try to change the text of an "EDIT"
control, I will not be able to delete the text buffer when finished because I do not know when the window procedure will finish processing the message.
So these are two ideas I can think of to access the UI controls from another thread:
ListViewX
", and when the UI thread receives this message, it updates ListViewX
, and when done, it deletes the string (which is allocated on the heap).Does one of these approaches provide some advantages over the other, and are there other approaches to do this?
Upvotes: 1
Views: 667
Reputation: 13401
I frequently use the following pattern (the arrows indicate a "uses" relationship):
+---------------+
| Communication | +-----------+
+--->+ Data Object +<---+---+ Thread #0 |
| | (thread safe) | | +-----------+
| +---------------+ +---+ Thread #1 |
| | +-----------+
| | ...
+-----+----+ | +-----------+
| Main (UI)| +---+ Thread N |
| Thread | +-----------+
+----------+
The Communication Data
object is threadsafe and typically ref-counted (important for non-GC-languages). The object provides a couple of typical methods (all optional, depending on the actual use case):
Because the data object fully takes care of itself, including synchronizing access to its data, and more or less automatic cleanup due to ref-counting, you end up with all that thread stuff nicely encapsulated into one dedicated class. I found this very handy in various situations.
Furthermore, the approach fully decouples the worker threads from the UI, so the threads don't even know whether or not there is an UI at all and how it looks like: is it a GUI? Is it a CLI? A web service maybe? Last not least it keeps the UI responsive, because the UI thread (or the equivalent thereof) can fully decide on its own when and how often to update the UI.
PS: Probably there's an official GOF name for it, don't know.
Upvotes: 3
Reputation: 612774
I know that in order to access the UI controls from another thread, I should use PostMessage(). However, PostMessage() is asynchronous, so for example if I try to change the text of an "EDIT" control, I will not be able to delete the text buffer when finished because I do not know when the window procedure will finish processing the message.
You are mistaken. There is no compulsion to use PostMessage
. And indeed for setting the window text of a control, you should not use PostMessage
. You need to send WM_SETTEXT
synchronously, for the very reasons you outline. If you don't send it synchronously then you don't know when to destroy the text buffer.
What you need to do is as follows:
SetWindowText
.SendMessageTimeout
to send the WM_SETTEXT
message.For windows in a different process, SetWindowText
is documented not to work. It's a little more complex than that, as Raymond explains, but you still, as a rule, should not use it on a window in a different process. So, for windows in a different process, use SendMessageTimeout
to send WM_SETTEXT
. The timeout is to prevent your application become hung if the target application is hung.
Upvotes: 2