News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

DrawText/DrawTextEx weird behavior if called in WM_PAINT

Started by 2B||!2B, August 05, 2023, 04:32:30 AM

Previous topic - Next topic

2B||!2B

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:


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...

zedd151

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 

2B||!2B

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".

zedd151


2B||!2B

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.

zedd151

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:

fearless

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.

jj2007

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

HSE

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

 
Equations in Assembly: SmplMath

Greenhorn

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.


Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

2B||!2B

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.

Greenhorn

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'?
Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

2B||!2B

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.

jj2007

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.

2B||!2B

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