The MASM Forum

General => The Campus => Topic started by: 2B||!2B on August 05, 2023, 04:32:30 AM

Title: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: 2B||!2B on August 05, 2023, 04:32:30 AM
Hey,

I had a weird issue when using DrawText/DrawTextEx API inside WM_PAINT (Just before EndPaint)
The problem is that when you move the window that has the text outside screen's working area, bringing the window back will make the text won't draw.


LOCAL ps:PAINTSTRUCT
LOCAL hBrush:HBRUSH
LOCAL hdc:HDC

.elseif EAX == WM_PAINT
invoke BeginPaint,hWin,addr ps

MOV hdc,EAX
invoke DrawText,hdc,chr$("This is a sample text"),-1,addr ps.rcPaint,DT_LEFT



invoke EndPaint,hWin,addr ps
                MOV EAX,0
                RET


Moving the window outside the screen working area (below taskbar in this case) and bringing it back:
(https://i.imgur.com/qYdU0vH.png)

ExtTextOut/TextOut doesn't have this issue.
Moving DrawText call after EndPaint will work as expected but then you have to use GetDC/RestoreDC
What's really the issue with DrawText here?
My assumption is that DrawText doesn't work properly with WM_PAINT DC.

Edit: For DrawText API, must use GetClientRect API for the window before calling it or the issue described here will appear. That still doesn't explain how other text drawing API's like ExtTextOut don't have this issue even with PAINTSTRUCT.rcPaint...
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: zedd151 on August 05, 2023, 05:16:31 AM
Did you try  "invoke SetBkMode, hDC, TRANSPARENT"?
Also uses GetClientRect here...

From a modified masm32 example:  (In WM_PAINT message handler)
Quoteinvoke BeginPaint, hWin, ADDR Ps
mov hDC, eax

invoke SetBkMode, hDC, TRANSPARENT

invoke GetClientRect, hWin, ADDR Rct

szText splashMsg, "Splash Screen"

invoke DrawText, hDC, ADDR splashMsg, 13, ADDR Rct, DT_LEFT

invoke EndPaint, hWin, ADDR Ps
Try it this way... using your own string of course 
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: 2B||!2B on August 05, 2023, 05:32:02 AM
I tried the TRANSPARENT mode. Same issue if we omit GetClientRect call but like I said, ExtTextOut will work without the need of GetClientRect and just by ps.rcPaint. Therefore, we can conclude that DrawText is a bit more "needy".
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: zedd151 on August 05, 2023, 05:33:41 AM
But does it work when using GetClienRect?
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: 2B||!2B on August 05, 2023, 05:37:39 AM
Quote from: zedd151 on August 05, 2023, 05:33:41 AMBut does it work when using GetClienRect?

Yes, it works and draws the text correctly even if you move the window out of screen and bring it back. I didn't know we must use GetClientRect for DrawText since we already have it in ps.rcPaint. Well, nothing in the documentation states that.
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: zedd151 on August 05, 2023, 05:40:36 AM
Well, okay then.  :thumbsup:  I have almost always seen GetClientRect used with DrawText iirc. But then again, I seldom have a need for DrawText with my projects.  :smiley:  I usually opt for using static controls where I need to use text...  :smiley:
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: fearless on August 05, 2023, 06:47:58 AM
Could be that you need to handle painting the background, and to override the WM_ERASEBKGND to tell it you are handling the background painting in the WM_PAINT yourself. So that would likely require using GetClientRect and handling brushes for painting the rect background before the text calls etc.

    .ELSEIF eax == WM_ERASEBKGND
        mov eax, 1
        ret

Also double buffering might help, and maybe WS_CLIPCHILDREN in the parent dialog/window perhaps.
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: jj2007 on August 05, 2023, 06:49:20 AM
invoke DrawText, hDC, ADDR splashMsg, 13, ADDR Rct, DT_LEFT

If Rct is a local RECT, its contents are undefined. Whatever happens to be on the stack will be used, so you might have Rct.left=8000... and that obviously is outside of the window.

One call to GetClientRect, and all is fine :thumbsup:

P.S.: Instead of DT_LEFT, use DT_CENTER or DT_VCENTER or DT_SINGLELINE
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: HSE on August 05, 2023, 07:06:28 AM
The RECT for DrawText define exact location of text. Then very often you must to make some calculations.

Just an piece of code to increase confusion :biggrin:
            mov    ecx , [xsi].ssy
            .if ecx > 150
                mov    eax , [xsi].total.top
                add    eax , [xsi].pxcabecera;RT.top
                  add    eax , 5
                  mov    TXT.top , eax
                add    eax , labelHeight
                mov    TXT.bottom , eax
            .else
                mov    eax , [xsi].RT.bottom   
                  sub    eax , 5
                  mov    TXT.bottom , eax
                sub    eax , labelHeight
                mov    TXT.top , eax
            .endif   
           
            mov    ecx , [xsi].ssx
            mov    edx , [xsi].pxeje1
            add    edx , [xsi].ancho
            sub    edx , labelWidth/2
            mov    ebx , [xsi].pxeje1
            add    ebx , labelWidth/2
            .if ecx <  ebx
                mov    ebx , [xsi].pxeje1
                mov    TXT.left , ebx
                add    ebx , labelWidth
                mov    TXT.right , ebx
            .elseif ecx >  edx
                mov    edx , [xsi].pxeje1
                add    edx , [xsi].ancho
                mov    TXT.right , edx
                sub    edx , labelWidth;/2-5
                mov    TXT.left , edx
            .else   
                add    ecx , labelWidth/2
                mov    TXT.right , ecx
                sub    ecx , labelWidth
                mov    TXT.left , ecx
            .endif
           
            invope xsi, RoundRect, memdc, TXT.left, TXT.top, TXT.right, TXT.bottom, 14, 14
            invope xsi, DrawText, memdc, addr buffer, -1, addr TXT,DT_CENTER or DT_VCENTER or DT_SINGLELINE

 
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: Greenhorn on August 05, 2023, 07:35:05 AM
Quote from: 2B||!2B on August 05, 2023, 04:32:30 AMLOCAL ps:PAINTSTRUCT
    LOCAL hBrush:HBRUSH
    LOCAL hdc:HDC
   
.elseif EAX == WM_PAINT
        invoke BeginPaint,hWin,addr ps
           
        MOV hdc,EAX
        invoke DrawText,hdc,chr$("This is a sample text"),-1,addr ps.rcPaint,DT_LEFT
               
        invoke EndPaint,hWin,addr ps
                MOV EAX,0
                RET

The rectangle rcPaint of the PAINTSTRUCT contains the invalid area that needs to be painted.
This excludes the clipping region. Debug the rcPaint when moving the window back into the working area and you will notice that only the pixels that were outside the working area and now get visible are within rcPaint rectangle. That's why your text is drawm at the bottom.

If you move or size a window the visible pixels are saved and copied back within the clipping rectangle.

So, if you size the window in height and use DrawText,hdc,chr$("This is a sample text"),-1,addr ps.rcPaint,DT_LEFT it will look the same as in your screenshot.


Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: 2B||!2B on August 05, 2023, 08:18:26 AM
Quote from: fearless on August 05, 2023, 06:47:58 AMCould be that you need to handle painting the background, and to override the WM_ERASEBKGND to tell it you are handling the background painting in the WM_PAINT yourself. So that would likely require using GetClientRect and handling brushes for painting the rect background before the text calls etc.

    .ELSEIF eax == WM_ERASEBKGND
        mov eax, 1
        ret

Also double buffering might help, and maybe WS_CLIPCHILDREN in the parent dialog/window perhaps.


Tried that already. Same result: DrawText needs a fresh RECT obtained by GetClientRect. Haven't tried double-buffer painting though. I suspect it to be the same result as the issue seems to be with the provided RECT.

Quote from: Greenhorn on August 05, 2023, 07:35:05 AM
Quote from: 2B||!2B on August 05, 2023, 04:32:30 AMLOCAL ps:PAINTSTRUCT
    LOCAL hBrush:HBRUSH
    LOCAL hdc:HDC
   
.elseif EAX == WM_PAINT
        invoke BeginPaint,hWin,addr ps
           
        MOV hdc,EAX
        invoke DrawText,hdc,chr$("This is a sample text"),-1,addr ps.rcPaint,DT_LEFT
               
        invoke EndPaint,hWin,addr ps
                MOV EAX,0
                RET

The rectangle rcPaint of the PAINTSTRUCT contains the invalid area that needs to be painted.
This excludes the clipping region. Debug the rcPaint when moving the window back into the working area and you will notice that only the pixels that were outside the working area and now get visible are within rcPaint rectangle. That's why your text is drawm at the bottom.

If you move or size a window the visible pixels are saved and copied back within the clipping rectangle.

So, if you size the window in height and use DrawText,hdc,chr$("This is a sample text"),-1,addr ps.rcPaint,DT_LEFT it will look the same as in your screenshot.




That's correct. The RECT obtained by GetClientRect differs from the one in PAINTSTRUCT.rcPaint as the first contains the full RECT of the window regardless of its painting status. However, as mentioned, ExtTextOut doesn't have this issue and works properly with PAINTSTRUCT.rcPaint.
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: Greenhorn on August 05, 2023, 09:23:51 AM
Quote from: 2B||!2B on August 05, 2023, 08:18:26 AMHowever, as mentioned, ExtTextOut doesn't have this issue and works properly with PAINTSTRUCT.rcPaint.

Could you post a code snippet how you use ExtTextOut? I guess you don't use ETO_CLIPPED in parameter 'options'?
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: 2B||!2B on August 05, 2023, 09:42:41 AM
Quote from: Greenhorn on August 05, 2023, 09:23:51 AM
Quote from: 2B||!2B on August 05, 2023, 08:18:26 AMHowever, as mentioned, ExtTextOut doesn't have this issue and works properly with PAINTSTRUCT.rcPaint.

Could you post a code snippet how you use ExtTextOut? I guess you don't use ETO_CLIPPED in parameter 'options'?

Here is how I called it
invoke ExtTextOut,hdc,0,0,ETO_OPAQUE,addr ps.rcPaint,chr$("This is a sample text"),22,0
I tried with ETO_CLIPPED. Couldn't reproduce the issue that DrawText has so my guess is that their implementation is different under the hood.
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: jj2007 on August 05, 2023, 09:53:46 AM
Quote from: 2B||!2B on August 05, 2023, 08:18:26 AMThe RECT obtained by GetClientRect differs from the one in PAINTSTRUCT.rcPaint as the first contains the full RECT of the window regardless of its painting status. However, as mentioned, ExtTextOut doesn't have this issue and works properly with PAINTSTRUCT.rcPaint.

While your remarks about the two RECTs are correct, it is very unlikely that DrawText and ExtTextOut behave differently. Post complete code with both of them, otherwise this thread remains pretty useless.
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: 2B||!2B on August 05, 2023, 11:44:08 AM
Quote from: jj2007 on August 05, 2023, 09:53:46 AMWhile your remarks about the two RECTs are correct, it is very unlikely that DrawText and ExtTextOut behave differently. Post complete code with both of them, otherwise this thread remains pretty useless.


.elseif EAX == WM_PAINT
invoke BeginPaint,hWin,addr ps

MOV hdc,EAX
invoke DrawText,hdc,chr$("This is a sample text"),22,addr ps.rcPaint,DT_LEFT
;invoke ExtTextOut,hdc,0,0,ETO_CLIPPED,addr ps.rcPaint,chr$("This is a sample text"),22,0


invoke EndPaint,hWin,addr ps
return 0


Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: Greenhorn on August 05, 2023, 06:13:01 PM
Quote from: 2B||!2B on August 05, 2023, 09:42:41 AMHere is how I called it
invoke ExtTextOut,hdc,0,0,ETO_OPAQUE,addr ps.rcPaint,chr$("This is a sample text"),22,0
I tried with ETO_CLIPPED. Couldn't reproduce the issue that DrawText has so my guess is that their implementation is different under the hood.

That's because you set for x and y the values 0,0. These values are relative to the HDC.
If you would set x = ps.rcPaint.left and y = ps.rcPaint.top the text would be drawn as in DrawText.

Internally DrawText calls ExtTextOut exactly like this, with x and y inside the defined rectangle.
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: 2B||!2B on August 06, 2023, 03:02:08 AM
Thanks Greenhorn,
It makes more sense now but also brings little more confusion as to what is the role of x/y in the lprect parameter of this function? Are they not used as they are specified explicitly?
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: Greenhorn on August 06, 2023, 03:42:15 AM
Quote from: 2B||!2B on August 06, 2023, 03:02:08 AMThanks Greenhorn,
It makes more sense now but also brings little more confusion as to what is the role of x/y in the lprect parameter of this function? Are they not used as they are specified explicitly?

https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-exttextoutw
[in] lprect
A pointer to an optional RECT structure that specifies the dimensions, in logical coordinates, of a rectangle that is used for clipping, opaquing, or both.
-----------------

With ETO_CLIPPED the text would not exceed the rectangle, same as DrawText without DT_NOCLIP.
However, this assumes that x and y is within the rectangle defined by lprect. And on the very first call of your WM_PAINT ps.rcPaint is 0, 0, clientWidth, clientHeight.
But I confirm, this is a little bit confusing since the documentation is here not clear enough on the first glance.
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: 2B||!2B on August 07, 2023, 04:48:07 AM
Thanks, Greenhorn.
Appreciate your time looking into this issue. :smiley:
Title: Re: DrawText/DrawTextEx weird behavior if called in WM_PAINT
Post by: jj2007 on August 11, 2023, 04:42:46 AM
Quote from: 2B||!2B on August 05, 2023, 11:44:08 AM
Quote from: jj2007 on August 05, 2023, 09:53:46 AMWhile your remarks about the two RECTs are correct, it is very unlikely that DrawText and ExtTextOut behave differently. Post complete code with both of them, otherwise this thread remains pretty useless.


.elseif EAX == WM_PAINT
invoke BeginPaint,hWin,addr ps

MOV hdc,EAX
invoke DrawText,hdc,chr$("This is a sample text"),22,addr ps.rcPaint,DT_LEFT
;invoke ExtTextOut,hdc,0,0,ETO_CLIPPED,addr ps.rcPaint,chr$("This is a sample text"),22,0


invoke EndPaint,hWin,addr ps
return 0

That doesn't look like "complete code" :rolleyes:

I refuse to stare at little snippets. You claim that DrawText behaves differently from ExtTextOut, you post a complete application that allows to verify your claim.