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!
Try Clearing the buffer before each pass through
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)
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
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
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)
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!
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
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?
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
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
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
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
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
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
The problem is with partial redraws and the location of the code that exchanges the values. If I move the code that exchanges the values to WM_KEYDOWN handler then the values don't get exchanged during the partial redraws and the problem goes away. Compile this as a console app:
;==============================================================================
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
printf("%d\t",ps.rcPaint.left)
printf("%d\t",ps.rcPaint.top)
printf("%d\t",ps.rcPaint.right)
printf("%d\n",ps.rcPaint.bottom)
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
mov eax, XX
mov edx, YY
mov XX, edx
mov YY, eax
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
in the code i posted earlier, i also put the dwtoa calls in the key handler
no need for that overhead in paint
Wow I think I like that len(addr buffer) trick, seems to work better now, thanks MichaelW!