The MASM Forum

General => The Campus => Topic started by: jj2007 on January 10, 2016, 09:18:56 PM

Title: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: jj2007 on January 10, 2016, 09:18:56 PM
I have a stupid little app (exe attached, source is a bit too complex) that shows a clock using inter alia CreateEllipticRgn and SetWindowRgn.

After reading several times the excellent Flicker-free Drawing (http://www.catch22.net/tuts/flicker-free-drawing) tutorial, I am still stuck (and no, CS_VREDRAW and CS_HREDRAW styles are not set). Same applies to possible causes explained here (http://msgroups.net/vc.mfc/system-wide-repaint-issue/569654), like LockWindowUpdate or WM_SETTINGCHANGE.

The problem is that when I repaint the time$ 12:34:56 once a second, other underlying top level windows repaint. Which probably means that somehow they get a WM_PAINT message via some broadcast mechanism. Since there is nothing to repaint, actually, i'd like to stop this broadcasting. Any ideas?

P.S.: When launching Notepad.exe, its menus flicker even if the entire Notepad window is far a way from the clock. So it is really a kind of system-wide repaint issue. Btw Firefox does NOT flicker.

P.P.S.: It turns out (with Spy++) that other windows get a WM_SYNCPAINT message. That can be suppressed by using the SWP_DEFERERASE flag in SetWindowPos. Problem is I am nowhere using SetWindowPos, so that cannot be the cause ::)

P.P.P.S.: Using GetDC instead of BeginPaint to paint the time "solves" the problem. So apparently BeginPaint/EndPaint are somehow involved in generating the WM_SYNCPAINT message.
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: Grincheux on January 10, 2016, 11:23:24 PM
It is 13:21:29 since five minutes!

Have you thought to WM_ERASEBCKGRND
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: Grincheux on January 10, 2016, 11:27:15 PM
I don't agree, if you tell MoveWindow that it must not send a WM_PAINT it does not send it.
Idem for SystemParametersInfo, and it depends which function is called. GET or SET and within the set function it is not obliged to send  a broadcast message.
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: Grincheux on January 10, 2016, 11:31:57 PM
http://f0dder.reteam.org/wm_timer.htm (http://f0dder.reteam.org/wm_timer.htm)

If the problem was from WM_TIMER?
Try to catch the timer after GetMessage and never pass it to dispatch message
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: jj2007 on January 10, 2016, 11:37:27 PM
Philippe,
Thanks but this is about WM_SYNCPAINT being sent to other top-level windows.
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: TWell on January 10, 2016, 11:43:56 PM
Like this here (https://blogs.msdn.microsoft.com/oldnewthing/20120723-00/?p=7073)
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: jj2007 on January 11, 2016, 01:54:08 AM
Quote from: TWell on January 10, 2016, 11:43:56 PM
Like this here (https://blogs.msdn.microsoft.com/oldnewthing/20120723-00/?p=7073)

Raymond writes: "When a window has been hidden, shown, moved or sized, the system may determine that it needs to send a WM_SYNC­PAINT message to the windows of other threads."

Point is, my windows gets an internal painting onto its own client area due to a SetTimer(). It doesn't get hidden, shown, moved or sized, so why the hell does the stupid OS instruct other windows to redraw?

I found a really clumsy workaround:

Case WM_TIMER
invoke GetDC, hWnd
push eax
push hWnd
push PtDC
mov PtDC, eax
GuiSetFill 4
GuiText 34.5, 70.0, Time$, bcol 0, fcol RgbCol(0, 0, 255)
pop PtDC
call ReleaseDC


Works like a charm, see attached exe, but this is really a hack, not a solution :(
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: Grincheux on January 11, 2016, 02:52:39 AM
That's what I said.
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: qWord on January 11, 2016, 03:12:48 AM
Quote from: jj2007 on January 11, 2016, 01:54:08 AMso why the hell does the stupid OS instruct other windows to redraw?
Because you decided to use error-prone "optimizations" in API code.
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: jj2007 on January 11, 2016, 03:22:54 AM
Quote from: qWord on January 11, 2016, 03:12:48 AM
Quote from: jj2007 on January 11, 2016, 01:54:08 AMso why the hell does the stupid OS instruct other windows to redraw?
Because you decided to use error-prone "optimizations" in API code.

Hmmm... that looks promising: Can you explain which "optimisation" triggers the sync message?
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: qWord on January 11, 2016, 03:34:37 AM
InvalidateRect@TimeProc -> hWnd
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: jj2007 on January 11, 2016, 04:05:46 AM
Quote from: qWord on January 11, 2016, 03:34:37 AM
InvalidateRect@TimeProc -> hWnd

:t

My fault :redface: I think I started that cbTimer as a frameless proc and changed my mind later. So with uses esi edi ebx the stack[3*4] arg was no longer hwnd but rather a zero...

Just for curiosity: How did you find it so quickly? You hooked InvalidateRect?
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: qWord on January 11, 2016, 04:21:49 AM
Quote from: jj2007 on January 11, 2016, 04:05:46 AM
Just for curiosity: How did you find it so quickly? You hooked InvalidateRect?
yes, I set a breakpoint an CALL in TimeProc. (after recognizing that you still handle message wrong...)
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: jj2007 on January 11, 2016, 05:37:51 AM
OK. To sum it up:

If you use InvalidateRect, hWnd, 0, 0 then make sure hWnd is really your window's handle. If you pass a zero instead, the OS sends a WM_SYNC­PAINT message to all top-level windows, and you'll get a lot of flicker all over the place.
Title: Re: Other top windows flicker: how to prevent WM_PAINT broadcast?
Post by: qWord on January 11, 2016, 05:51:07 AM
There is no reason to know WM_SYNCPAINT, because it is a system internal message.
msdn actual explain it very well:
Quote from: msdn: InvalidateRect, hWndA handle to the window whose update region has changed. If this parameter is NULL, the system invalidates and redraws all windows, not just the windows for this application, and sends the WM_ERASEBKGND and WM_NCPAINT messages before the function returns. Setting this parameter to NULL is not recommended.