News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

TEXTOUT Question

Started by 44mag, April 03, 2012, 06:16:41 AM

Previous topic - Next topic

44mag

Hello all, can someone tell me why the following snippet of code produces the following results:

.data
XX DWORD 1
YY DWORD 123456

.data?
buffer db 128 dup(?)
...
...
    .if uMsg==WM_PAINT
   ...
   ...
   invoke dwtoa,XX,ADDR buffer
   invoke TextOut,hdc,0,100,ADDR buffer,SIZEOF buffer
   invoke dwtoa,YY,ADDR buffer
   invoke TextOut,hdc,0,300,ADDR buffer,SIZEOF buffer

    .elseif uMsg==WM_CREATE         
        invoke InvalidateRect,hWnd,NULL,TRUE
        invoke UpdateWindow,hWnd

    .elseif uMsg==WM_CHAR           
        invoke InvalidateRect,hWnd,NULL,TRUE
        invoke UpdateWindow,hWnd

When it first runs it correctly displays:

1


123456


But the second time around when I press a key I get:

1 3456


123456

The numbers show up fine in a messagebox every time though.  Thanks for any info!

Neil

Try Clearing the buffer before each pass through

MichaelW

Instead of passing the overall length of the buffer, try passing the length of the string that dwtoa placed in the buffer.

For example:

invoke TextOut, hdc, 0, 300, ADDR buffer, len(ADDR buffer)
eschew obfuscation

dedndave

Michael, he may want to overwrite the old stuff   :P

pretty easy to use Neil's idea
but, you might use a smaller (global) buffer to make it easier to clear out, too
a buffer of 12 bytes (3 dwords) will be large enough for any dword value and easy to clear

also, instead of setting the ascii string into the buffer during WM_PAINT...
clear the buffer and set the string when the string value requires update (i.e. not during WM_PAINT)
then use Invalidate and Update to cause WM_PAINT to update the screen
        .DATA?
hWin    dd ?
buffer  dd 3 dup(?)

        .CODE
;
;
;
        mov     edx,offset buffer
        xor     eax,eax
        mov     [edx],eax
        mov     [edx+4],eax
        mov     [edx+8],eax
        INVOKE  dwtoa,XX,edx
        INVOKE  InvalidateRect,hWin,NULL,TRUE
        INVOKE  UpdateWindow,hWin

dedndave

a little clarification on that last part...

first, windows sends a WM_PAINT message whenever all or part of the window needs to be redrawn
this happens if you restore it from minimized,
but probably more often if your window is brought to the front from behind some other window
it is nice if you can minimize the execution time in the paint routine
that means - no need to repeatedly convert the dword into an ascii string, unless it has changed value

second, when you change a small part of the client window, as in this case,
it would be nice if we only invalidate and update the area that requires it
this may take a bit of code - lol
the part where we invalidate might not be too bad - a simple rectangle that outlines where this piece of text goes
but the paint routine then has to know how to paint only the part that requires updating   :P
most of us are lazy, in that respect, and you will see a lot of code that simply updates the entire client
that's because it is easier to write the code that way - that doesn't mean it's the best way to do it
one thing you can do is to split up the client area with smaller children windows or static text controls

zemtex

I recommend you use a dib section for the entire window and then split the dib section (virtually) and not actually. If you use several static controls, you will only be met with unwanted complexity and you will have problems performing graphics operations that scale across all sections at the same time, some times you need to do things that scales all over. Use a dib section, and don't always use WM_PAINT, you can get the dc by using GetDC too if you need to update small parts of it.

I have added a grid demo that uses this approach, you can see it is quite responsive. Use right mouse button to clear the screen again (redraw grid)
I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

44mag

It looks like I may have to go with the buffer clearing route.   But why is it not necessary for a messagebox?  I added them in like so:

  invoke dwtoa,XX,ADDR buffer
  invoke TextOut,hdc,0,100,ADDR buffer,SIZEOF buffer
  invoke MessageBox, NULL, buffer, NULL,NULL
  invoke dwtoa,YY,ADDR buffer
  invoke TextOut,hdc,0,300,ADDR buffer,SIZEOF buffer
  invoke MessageBox, NULL, buffer, NULL,NULL

And the numbers show up fine in the messageboxes, is there a particular reason why?

Thanks again for all the info!

dedndave

for MessageBox, it uses a zero-terminated string
so, the first zero byte is where it stops looking at the buffer
you have to clear out the rest of your buffer because, no matter how long the string is, all characters in the buffer are displayed

MichaelW

44mag,

TextOut does not recognize nulls as string terminators -- it just goes with whatever length you pass it. Do you have a specific reason for displaying the entire buffer, instead of just displaying the string that dwtoa stored in the buffer?
eschew obfuscation

dedndave

Michael
if you display the value 12345
then update it with the value 1
the old "1" gets overdrawn by the new "1"
the old "2" gets overdrawn by the new null
if you don't display the entire buffer (ending with nulls or spaces, of course), the '345' would remain

problem is - if it is proportional text, it may not work too well if you overdraw '99999' with '11111' - lol - oops
there are ways around it, of course
easier to use "Terminal" or some other monospace font   :U

MichaelW

What is the problem with this:

;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================
    .data
        XX      dd          123456789
        YY      dd          12
        ps      PAINTSTRUCT <>
    .data?
        buffer  db          128 dup(?)
    .code
;==============================================================================

DlgProc proc uses ebx hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    SWITCH uMsg

      CASE WM_PAINT

        invoke BeginPaint, hwndDlg, ADDR ps
        mov eax, XX
        mov edx, YY
        mov XX, edx
        mov YY, eax
        invoke dwtoa,XX,ADDR buffer
        invoke TextOut,ps.hdc,10,100,ADDR buffer,len(ADDR buffer)
        invoke dwtoa,YY,ADDR buffer
        invoke TextOut,ps.hdc,10,200,ADDR buffer,len(ADDR buffer)
        invoke EndPaint, hwndDlg, ADDR ps

      CASE WM_KEYDOWN

        invoke InvalidateRect,hwndDlg,NULL,TRUE
        invoke UpdateWindow,hwndDlg

      CASE WM_CTLCOLORDLG

        invoke GetStockObject, WHITE_BRUSH
        return eax

      CASE WM_COMMAND

        SWITCH wParam

          CASE IDCANCEL

            invoke EndDialog, hwndDlg, 0

        ENDSW

      CASE WM_CLOSE

        invoke EndDialog, hwndDlg, 0

    ENDSW

    return FALSE

DlgProc endp

;==============================================================================
start:
;==============================================================================

    Dialog "Test", "MS Sans Serif",10, \
           WS_OVERLAPPEDWINDOW or DS_CENTER, \
           0,0,0,200,150,1024

    invoke GetModuleHandle, NULL

    CallModalDialog eax,0,DlgProc,NULL

    exit

;==============================================================================
end start
eschew obfuscation

dedndave

1) i don't know why it works as well as it does - lol
not too sure about the len macro, there - never used it

2) it doesn't work all that well
move a window in front of it, then drag that window away and reveal the dialog box
i don't know why that happens, either - lol
it looks ok, in that respect

dedndave

i still can't say how or why TextOut erases the other characters
i am guessing that erase background takes care of it for you

anyway, this works a little better, and it demonstrates what i said in my 1st post
;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================
    .data

XX      dd          2147483647
YY      dd          1
ps      PAINTSTRUCT <>

    .data?

buffer1  db          128 dup(?)
buffer2  db          128 dup(?)

    .code

;==============================================================================

UpdBuf  PROC

        mov     eax,XX
        mov     edx,YY
        mov     XX,edx
        mov     YY,eax
        INVOKE  dwtoa,edx,offset buffer1
        INVOKE  dwtoa,YY,offset buffer2
        ret

UpdBuf  ENDP

;==============================================================================

DlgProc proc uses ebx hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    SWITCH uMsg

      CASE WM_PAINT

        INVOKE  BeginPaint,hwndDlg,offset ps
        INVOKE  TextOut,ps.hdc,10,100,offset buffer1,len(offset buffer1)
        INVOKE  TextOut,ps.hdc,10,200,offset buffer2,len(offset buffer2)
        INVOKE  EndPaint,hwndDlg,offset ps

      CASE WM_KEYDOWN

        call    UpdBuf
        INVOKE  InvalidateRect,hwndDlg,NULL,TRUE
        INVOKE  UpdateWindow,hwndDlg

      CASE WM_CTLCOLORDLG

        invoke GetStockObject, WHITE_BRUSH
        return eax

      CASE WM_COMMAND

        SWITCH wParam

          CASE IDCANCEL

            invoke EndDialog, hwndDlg, 0

        ENDSW

      CASE WM_CLOSE

        invoke EndDialog, hwndDlg, 0

    ENDSW

    return FALSE

DlgProc endp

;==============================================================================
start:
;==============================================================================

        call    UpdBuf

    Dialog "Test", "MS Sans Serif",10, \
           WS_OVERLAPPEDWINDOW or DS_CENTER, \
           0,0,0,200,150,1024

    invoke GetModuleHandle, NULL

    CallModalDialog eax,0,DlgProc,NULL

    exit

;==============================================================================
end start

dedndave

        INVOKE  InvalidateRect,hwndDlg,NULL,TRUE
yah - we are erasing the background when a key is pressed   :P
change that to FALSE, and you'll see what i meant

dedndave

all in all, i guess that's not a bad solution, either, Michael
as long as we are not also painting the entire client
it does take care of the proportional font issue

we really haven't done a lot of code timing in this area
some in past threads if you search - Tedd and JimG, i think
but, then, this is the campus and not the best place for all that
still, we should be able to advise properly   :P

Zemtex's thought on dib section may be a way to go
but, his example programs just display a green background on my machine   :bg
and - alas - no source to see what is going on   :(
i am not a big fan of using someone's DLL, either - but it might be something to learn from