BACKGROUND. We all know that CWnd::PostMessage() and CWnd::SendMessage() both place a message in the queue and the difference is that the latter does not return until the message is processed. To me this can be useful when creating an application with more than one thread running, in which for example CWnd::SendMessage(WM_PAINT, 0, 0) can be called from a worker thread to make sure that OnPaint() handler in the main thread is executed and returned before the worker thread does anything further. This eliminates the need to "manually" put the worker thread to sleep.
PROBLEM. From a worker thread, I need to invalidate the whole client area of my main (and only) window, and make sure that OnPaint() handler has finished execution before the worker thread does anything further.
ATTEMPTED SOLUTIONS. I could call CWnd::SendMessage(WM_PAINT, 0, 0) from my worker thread. But the problem with this is that at this point in the execution of my application, the invalid region is empty, so that even if OnPaint() is executed, it won't make any visual difference. Alternatively, I could call CWnd::Invalidate(TRUE) from my worker thread. But the problem with this is that CWnd::Invalidate() does NOT wait until WM_PAINT is processed before it returns, the result is that OnPaint() and worker thread code are executed "simultaneously" (well, not really, the scheduler makes it virtually simultaneous), causing chaos in the display.
HELP PLEASE. I was imagining a way to invalidate the whole client area without actually sending the WM_PAINT message, and then I can call CWnd::SendMessage(). Is this possible? Please help. Thank you in advance.
henky@nok.co.id
September 10th, 2007, 06:25 AM
You can synchronize them using event. Since you shouldn't send WM_PAINT directly to
window.
The WM_PAINT message is generated by the system and should not be sent by an application.
Fatboy
September 10th, 2007, 06:31 AM
What do you mean by "synchronising using event"?
What I want to do is effectively obtain or be able to implement InvalidateNoReturn() or some similar function, which effectively sends a WM_PAINT to the main window invalidating the whole client area without returning. I know I shouldn't send WM_PAINT directly from application under normal circumstances, and I know the reasons behind it. But in this case it seems I need to.
henky@nok.co.id
September 10th, 2007, 06:43 AM
What i mean is, invalidate the window and wait until window finish to repainting client area.
May be critical section is better than event, because critical section is faster.
Fatboy
September 10th, 2007, 07:14 AM
That's my point, I can't JUST invalidate and wait until the worker thread finishes before repainting the client area. I HAVE TO REPAINT THE CLIENT THERE AND THEN! RIGHT AT THAT POINT OF EXECUTION! WITHOUT THE WORKER THREAD DOING ANYTHING AT ALL! The worker thread has to come to a hault and wait for the window to repaint right then!!!!!!!!! That was the point of me posting on codeguru.
Boris K K
September 10th, 2007, 12:09 PM
Fatboy,
1. It would be nice if you edit your last post.
2. See if UpdateWindow (http://msdn2.microsoft.com/en-us/library/ms534874.aspx) is what you need.
JVene
September 10th, 2007, 08:23 PM
I HAVE TO REPAINT THE CLIENT THERE AND THEN! RIGHT AT THAT POINT OF EXECUTION! WITHOUT THE WORKER THREAD DOING ANYTHING AT ALL! The worker thread has to come to a hault and wait for the window to repaint right then!!!!!!!!!
We do understand. We've been there before (many of us have anyway) - some of us for decades.
Calm down (all caps is the equivalent of yelling, according to the common etiquette of most forums).
The notion of the event is a valid one. If you think about it with greater care, it may even occur to you.
Before I return to that theme, let me point out that calling sendmessage from a thread is a bad idea. It means that the message is processed on the thread's execution, not on the main GUI thread's execution. Many processes will fail to work properly if they're not executed on the main GUI thread, and paint is among them. It's even possible that a paint message will fire on the main GUI thread while your sendmessage is processing - it may depend on the framework as to what to expect in that circumstance.
While I don't actually agree with the event method, it could work like this. You post a paint message, set an event to non signaled state (which is like setting a bool to false), then 'wait' on the event (using the waitonsingleobject function). The paint message would be processed on the main GUI thread as quickly as possible, while your thread is blocked, waiting on that to happen. There may be other messages required for processing other than the WM_PAINT by itself, and a sendmessage could interfere with that schedule of events.
However, when the paint is completed, it would signal the event (similar to setting a bool to true). The operating system will then release your wait in the thread, and it can continue - in full knowledge that the paint has completed.
This effectively does what you've asked for.
There is an alternative, depending on how far you're willing to go.
The act of painting is performed using a DC, but any DC will do with respect to the calls on that DC (the selectobject, drawnnnn, whatever the DC does to do it's painting). You could create a function that 'does' the painting which is independent of the WM_PAINT response function. That WM_PAINT response would be reduced to just the creation of the CPaintDC (mfc), calling this proposed paint funciton - passing the paintDC as the parameter, then deleting the CPaindDC (falling from scope).
This means you could call this painting function from another context with a different DC. Depending on what you're doing in the painting, you can therefore create a CClientDC in your thread, call the paint function, know that the painting has completed, and continue. The painting is done in the background, and no WM_PAINT message is fired (an no invalidate is required).
This DOES require that you synchronize painting against the CClientDC painting, probably with a boolean. If a WM_PAINT message happens to fire while your background painter is busy, you can simply skip the WM_PAINT work (just don't call the paint function). Let the background, which is obviously in progress, complete - and suffice as that message's painting.
There may be other design approaches to solving the problem, which then begs the question, what is the design criteria that places you in the position of requiring that a function be blocked while a paint is completed?
That really sounds to me like a 3 step process that may be better broken into 3 stages, prep/paint/finish - each 'chained' to each other - but then I'm accustomed to queued threading which supports this notion easily.
henky@nok.co.id
September 10th, 2007, 09:00 PM
That's why i said "synchronizing them using event".
You can synchronize them using event.
May be critical section is better than event, because critical section is faster.
JVene
September 10th, 2007, 09:51 PM
Yes, henky@nok.co.id, I saw it - sorry, I didn't think to reference your post while I was typing - my mistake.
And it would work well, too.
I like the CClientDC approach, myself - it's not that it's cleaner, it can actually be a little dirtier, especially with respect to optimized painting in small regions, and there are circumstances where using the event would work better.
I think event is more applicable than a critical section. With an event, a thread can be blocked without another thread 'holding' the critical section, and released on a single call to signal, meeting the design requirement. A critical section would block only if another thread is locking that critical section, which can't be arranged immediately (the paint won't be able to lock the critical section until the GUI thread processes the message).
henky@nok.co.id
September 10th, 2007, 10:07 PM
i'm sorry too, JVene. :)
Anyway, synchronizing among threads is important concept in multi threading programming
what ever the way to do.
What i want to say in my previous post is, even though we face problems in programming
stage, we can't do something that against OS concept. This is a common sense.
Thanks for additional explanation, JVene.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.