Link to home
Start Free TrialLog in
Avatar of thready
thready

asked on

C++ sendng messages to GUI controls from different threads (thread - safety)

Hi Experts,
I would like to set my mind straight on this once and for all.  When calling GUI controls from other threads, I know you have to send messages.  Can thIs be the case for non-GUI objects?

As an example to help answer this question, I'm writing a progress bar control that I want to have the method "SetCurrentProgress(CString strText, double dPercentProgress)".  I primarily want to know how to make this function thread-safe, and easily accessible to my whole application (I guess making it global is the easiest/best way for easy access?)

My usual approach is to have a SendMessage call within the SetCurrentProgress function so that the message is sent to the window of the progress bar and ends up being on the GUI thread instead of whatever the calling thread is on.  But my progress bar doesn't update.  So I try doing MessageQueueHelper::DoEvents to force the events in the event loop to occur, and this seems problematic as well.....  I've had this kind of thing more or less working nicely before, but I really need to know the best way, and understand what's going wrong exactly when things don't seem to work.

Thanks for your help!
Mike
ASKER CERTIFIED SOLUTION
Avatar of HooKooDooKu
HooKooDooKu

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of thready
thready

ASKER

You're right tgerbert- there will often be situations where SendMessage will block and cause deadlocks.  Thanks HooKooDooKu, your answer is very thorough, but there's the key element I'm still missing- where do I put the SendMessage call?  I'm creating a progress bar and I want to 1) have easy access throughout the program to the progress bar and 2) not have to worry about calling PostMessage - I'd rather call a nice function that will call PostMessage for me...  This seems easy, but I always have some trouble with it.  Like now, I have my progress bar as a global variable and the program is crashing in RegisterWindowClass (custom control stuff) on the call to AfxGetInstanceHandle() - because current instance handle is null by making the progress bar global...  I don't understand.

So I revert to using a class variable in the parent dialog instead of making the progress bar global and now I have to worry about how I need to give my thread access to this-- which I find makes things a mess.  Globals are not the most kosher thing in the world, but they are definitely cleaner than the alternative.  After all, my app only has 1 progress bar.  Anyway.  So now I'm trying to figure out how to give this thread access to my progress bar in the most elegant way possible.

Thread (for testing my control)
    for(int i = 0; i < 100; i++)
         SomehowGetProgressPointer->SetCurrentProgress(i);

inside ProgressBar::SetCurrentProgress(int nProgress)
        PostMessage(WM_PROGRESS_UPDATE, 0, nProgress)

ON_MESSAGE(WM_PROGRESS_UPDATE, OnProgressUpdate)

LONG OnProgressUpdate(WPARAM wParaam, LPARAM lParam)
        m_nProgress=  (int)lParam;
        Invalidate();

Does this make sense?  Is there a better way?  How do I get access to the progress control in a clean way?

Sorry for the long-winded question - but this has been bugging me for far too long and I really want to make this clear for myself.

Thanks a lot for your help with this gentlemen!

Mike
Avatar of thready

ASKER

There is one alternative that I currently use that I don't like.  I just send messages and I keep a pointer to the window handle of the object that handles the message...   I just wish there were a better way....
Avatar of thready

ASKER

... a more object oriented way...
Avatar of thready

ASKER

After reading more about this online, I think it's actually better to pass HWNDs instead of accessing actual objects - it's a better way to decouple the GUI from the work being done.  So this ends this question and I'm satisfied.  Thanks again!