NOT displaying the trailing zero and Restoring Fonts correctly...

Started by The SharK, January 28, 2008, 01:06:47 PM

Previous topic - Next topic

The SharK

Why is it, that I have to write "-1", at the end of TextOut, to make the text NOT display the trailing zero  ::)
and
Do I "restore" the original font in the right manner everytime I create a new font  :eek

.386
.model flat,stdcall
option casemap:none

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

RGB macro red,green,blue
        xor eax,eax
        mov ah,blue
        shl eax,8
        mov ah,green
        mov al,red
endm

.data
ClassName       db "SimpleWinClass",0
AppName         db "Our First Window",0
TestString      db "This is written with the OEM_CHARSET",0
NormalWriting_1 db "I'm writing in the original font ;-)",0
NormalWriting_2 db "I'm now writing in the original font again ;-)",0
RussianString   db "This is written with the Russian Font !",0
RussianWriting  db "I'm STILL writing with the last Selected Font !",0
VietnamString   db "This is written with the Vietnamese Font !",0
FontName        db "script",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?

.code
start:
    invoke  GetModuleHandle, NULL
    mov     hInstance,eax
    invoke  GetCommandLine
    mov     CommandLine,eax
    invoke  WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke  ExitProcess,eax


WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_WINDOW+1
    mov   wc.lpszMenuName,NULL
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
           hInst,NULL
    mov   hwnd,eax
    INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
    INVOKE UpdateWindow, hwnd
        .WHILE TRUE
                INVOKE GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                INVOKE TranslateMessage, ADDR msg
                INVOKE DispatchMessage, ADDR msg
        .ENDW
   
    mov     eax,msg.wParam
    ret
WinMain endp


WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
  LOCAL hdc:HDC
  LOCAL ps:PAINTSTRUCT
  LOCAL hfont:HFONT
  LOCAL hVietnameseFont:HFONT
  LOCAL hRussianFont:HFONT

    .IF uMsg==WM_DESTROY
    invoke PostQuitMessage,NULL

    .ELSEIF uMsg==WM_PAINT
        invoke BeginPaint,hWnd, ADDR ps
        mov    hdc,eax
        invoke TextOut,hdc,380,270,ADDR NormalWriting_1,SIZEOF NormalWriting_1 -1    ; Why "-1" here ?
        invoke CreateFont,24,16,0,0,400,0,0,0,OEM_CHARSET,\
                          OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
                          DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
                          ADDR FontName
    invoke SelectObject, hdc, eax
    mov    hfont,eax
    RGB    255,0,0
    invoke SetTextColor,hdc,eax
    RGB    0,0,0
    invoke SetBkColor,hdc,eax
    invoke TextOut,hdc,380,300,ADDR TestString,SIZEOF TestString
    invoke SelectObject,hdc, hfont
   
   
    invoke CreateFont,0,0,0,0,400,0,0,0,VIETNAMESE_CHARSET,\
                      OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
                      DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
                      ADDR FontName
    invoke SelectObject, hdc, eax
    mov    hVietnameseFont,eax
    RGB    255,0,0
    invoke SetTextColor,hdc,eax
    RGB    0,0,0
    invoke SetBkColor,hdc,eax
    invoke TextOut,hdc,380,330,ADDR VietnamString,SIZEOF VietnamString -1    ; Why "-1" here ?
    invoke SelectObject,hdc, hfont   

    invoke CreateFont,0,0,0,0,400,0,0,0,RUSSIAN_CHARSET,\
                      OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
                      DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
                      ADDR FontName
    invoke SelectObject, hdc, eax
    mov    hRussianFont,eax
    RGB    255,0,0
    invoke SetTextColor,hdc,eax
    RGB    0,0,0
    invoke SetBkColor,hdc,eax
    invoke TextOut,hdc,380,360,ADDR RussianString,SIZEOF RussianString -1    ; Why "-1" here ?
    invoke TextOut,hdc,380,390,ADDR RussianWriting,SIZEOF RussianWriting -1    ; Why "-1" here ?
    invoke SelectObject,hdc, hfont
    RGB    0,0,0
    invoke SetTextColor,hdc,eax
    RGB    255,255,255
    invoke SetBkColor,hdc,eax
    invoke TextOut,hdc,380,420,ADDR NormalWriting_2,SIZEOF NormalWriting_2 -1    ; Why "-1" here ?
    invoke EndPaint,hWnd, ADDR ps

    .ELSE
    invoke DefWindowProc,hWnd,uMsg,wParam,lParam
    ret

    .ENDIF

  xor    eax,eax
  ret
WndProc endp
end start



regards,

The SharK
Always look at the good things in life...

Tedd

Because TextOut requires you to tell it HOW MANY characters to print; it doesn't know/care whether your string is null-terminated or not. So when you do "SIZEOF yourstring" you're getting the length of the string including its terminating zero, so you have to subtract 1 to get the length without the zero. In other words, the terminating null isn't required for such strings (unless you plan to use them elsewhere, where it is required.)
When you do a "SelectObject" it returns the object you just replaced. So, you don't actually need to select yours in, then put the old one back, then put another of yours in, then put the old one back... You can simply select yours in and save the previous one, then select another of yours in, and another, ..., and then finally restore the original when you've finished.
Also, remember to delete the fonts you've created when you no longer need them. In your case, it might be a better idea to create all of the fonts you need (in WM_CREATE) and save all of their handles for the lifetime of the program, then delete them all again on close (in WM_DESTROY)
No snowflake in an avalanche feels responsible.

The SharK

Hi Tedd

Great advice  :thumbu

I have adjusted the code according to your advice:

But now the SelectObject doesn't select anything - they all returns ZERO  :dazzled:

regards,

The SharK

.386
.model flat,stdcall
option casemap:none

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

RGB macro red,green,blue
        xor eax,eax
        mov ah,blue
        shl eax,8
        mov ah,green
        mov al,red
endm

.data
ClassName       db "SimpleWinClass",0
AppName         db "Our First Window",0
OEMString       db "This is written with the OEM_CHARSET",0
NormalString_1  db "I'm writing in the original font ;-)",0
NormalString_2  db "I'm now writing in the original font again ;-)",0
RussianString_1 db "This is written with the Russian Font !",0
RussianString_2 db "I'm STILL writing with the last Selected Font !",0
VietnamString   db "This is written with the Vietnamese Font !",0
FontName        db "script",0

.data?
hInstance       HINSTANCE   ?
CommandLine     LPSTR       ?

.code
start:
    invoke  GetModuleHandle, NULL
    mov     hInstance,eax
    invoke  GetCommandLine
    mov     CommandLine,eax
    invoke  WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke  ExitProcess,eax


WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_WINDOW+1
    mov   wc.lpszMenuName,NULL
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
           hInst,NULL
    mov   hwnd,eax
    INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
    INVOKE UpdateWindow, hwnd
        .WHILE TRUE
                INVOKE GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                INVOKE TranslateMessage, ADDR msg
                INVOKE DispatchMessage, ADDR msg
        .ENDW
   
    mov     eax,msg.wParam
    ret
WinMain endp


WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
  LOCAL hdc   :HDC
  LOCAL ps    :PAINTSTRUCT
  LOCAL hfont :HFONT
  LOCAL hOEM  :HFONT
  LOCAL hViet :HFONT
  LOCAL hRuss :HFONT 

    .IF uMsg==WM_DESTROY
        invoke DeleteObject, hOEM       ; Deletes the OEM_CHARSET font object.
        invoke DeleteObject, hViet      ; Deletes the VIETNAMESE_CHARSET font object.
        invoke DeleteObject, hRuss      ; Deletes the RUSSIAN_CHARSET font object.

        invoke PostQuitMessage,NULL     ; The PostQuitMessage function indicates to the system that
                                        ; a thread has made a request to terminate (quit).
                                        ; It is typically used in response to a WM_DESTROY message.


    .ELSEIF uMsg==WM_CREATE
        invoke CreateFont, 24, 16, 0, 0, 400, 0, 0, 0, OEM_CHARSET,\
                          OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,\
                          DEFAULT_QUALITY, DEFAULT_PITCH or FF_SCRIPT,\
                          ADDR FontName
        mov hOEM, eax

        invoke CreateFont, 0, 0, 0, 0, 400, 0, 0, 0, VIETNAMESE_CHARSET,\
                      OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,\
                      DEFAULT_QUALITY, DEFAULT_PITCH or FF_SCRIPT,\
                      ADDR FontName
        mov hViet, eax

        invoke CreateFont, 0, 0, 0, 0, 400, 0, 0, 0, RUSSIAN_CHARSET,\
                      OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,\
                      DEFAULT_QUALITY, DEFAULT_PITCH or FF_SCRIPT,\
                      ADDR FontName
        mov hRuss, eax   
       
    .ELSEIF uMsg==WM_PAINT
        invoke BeginPaint, hWnd, ADDR ps
        mov    hdc, eax
        invoke TextOut, hdc, 380, 270, ADDR NormalString_1, SIZEOF NormalString_1 -1

        invoke SelectObject, hdc, hOEM
        mov    hfont, eax               ; IMPORTANT! - Save the handle of the old font !!!
        RGB    255, 0, 0
        invoke SetTextColor, hdc, eax
        RGB    0, 0, 0
        invoke SetBkColor, hdc, eax
        invoke TextOut, hdc, 380, 300, ADDR OEMString, SIZEOF OEMString -1 
       
        invoke SelectObject, hdc, hViet
        RGB    255, 0, 0
        invoke SetTextColor, hdc, eax
        RGB    0, 0, 0
        invoke SetBkColor, hdc, eax
        invoke TextOut, hdc, 380, 330, ADDR VietnamString, SIZEOF VietnamString -1

        invoke SelectObject, hdc, hRuss
        RGB    255, 0, 0
        invoke SetTextColor, hdc, eax
        RGB    0, 0, 0
        invoke SetBkColor, hdc, eax
        invoke TextOut, hdc, 380, 360, ADDR RussianString_1, SIZEOF RussianString_1 -1
        invoke TextOut, hdc, 380, 390, ADDR RussianString_2, SIZEOF RussianString_2 -1
        RGB    0, 0, 0
        invoke SetTextColor,hdc, eax
        RGB    255, 255, 255
        invoke SetBkColor,hdc, eax
        invoke TextOut, hdc, 380, 420, ADDR NormalString_2, SIZEOF NormalString_2 -1
        invoke SelectObject,hdc, hfont
        invoke EndPaint,hWnd, ADDR ps

    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret

    .ENDIF

  xor    eax, eax
  ret
WndProc endp


end start
Always look at the good things in life...

The SharK

hmmm

I think the answer is:

make the handles GLOBAL in the .data section !


.data
hfont    dd HFONT
hOEM    dd HFONT
hViet     dd HFONT
hRuss    dd HFONT


this worked though !


is this the correct solution ?


regards,

The SharK
Always look at the good things in life...

jj2007

Quote from: The SharK on January 28, 2008, 04:03:46 PM
make the handles GLOBAL in the .data section !
...
is this the correct solution ?

Yes indeed. WndProc is a callback procedure, which means that every time it gets called, there will be a completely virgin set of local variables. Note also that local variables are NOT zero-initialised.

The SharK

Hi jj2007


should I make:

LOCAL hdc : HDC
LOCAL ps   : PAINTSTRUCT

GLOBAL ? they seem to work both LOCAL or GLOBAL  ::)
Always look at the good things in life...

jj2007

Quote from: The SharK on January 28, 2008, 04:27:40 PM
Hi jj2007


should I make:

LOCAL hdc : HDC
LOCAL ps   : PAINTSTRUCT

GLOBAL ? they seem to work both LOCAL or GLOBAL  ::)

They work local if they are assigned within the same CASE; e.g. if you process WM_PAINT:

  .ELSEIF uMsg==WM_PAINT
        invoke BeginPaint, hWnd, ADDR ps
        mov    hdc, eax
...
    invoke EndPaint,hWnd, ADDR ps


That's fine: you assign hdc at the beginning, and use the same ps from BeginPaint to EndPaint

The SharK

ok,
so when you use LOCAL in the beginning of WndProc, you can't "mix" these
variables within every WM_ message.
I.E. if I create a font within WM_CREATE, I can't delete the object in WM_DESTROY, if the
handle to the font are LOCAL !
But if the handle to the font are GLOBAL, then I can use WM_CREATE to create the font,
and use WM_DESTROY to destroy it afterwards.

Conclusion:
So within every WM_ message, the code is LOCAL to the exact WM_ message right ?
and to make use of the variable in every WM_ message, you have to make it GLOBAL.

does this make any sense, or have I blurred it all  :bg

regards,

The SharK
Always look at the good things in life...

jj2007

Quote from: The SharK on January 28, 2008, 06:37:36 PM
So within every WM_ message, the code is LOCAL to the exact WM_ message right ?
and to make use of the variable in every WM_ message, you have to make it GLOBAL.

Absolutely clear and correct :green

The SharK

Always look at the good things in life...