News:

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

Main Menu

TextOut to Bitmap

Started by Haleakala, March 18, 2013, 02:49:21 PM

Previous topic - Next topic

Haleakala

Hello.

I'm a noob at assembly.  I am having some difficulties understanding both concept and code. 
I have a homework assignment which states that has three aspects:
Create a window that will...
1. write text to a point where a mouse click is started
2. draw rectangles and ellipses with different color choices
3. Send a message Box to the user

I have done all of these separately, but I do not know how to incorporate these functions into the same window/ program.

I can sort of do 1 or 2, but only if bitblt is commented out.  I should be able to select "Text" from the menu, click and area, start typing, then click another area, and start a new text string. 

I'm thinking it must be something to do with a DC? where that I type should be sent to the same handle as the bitmap?  Then I would have to know how to erase the Keyboard String or make a loop such that the old one remains existing when I attempt to make a new textbox.

Any guidance will be much appreciated.  Here is the code that I've been trying to manipulate thus far:

.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

.DATA               ; initialized data
ClassName      db   "SimpleWinClass",0
AppName        db   "Our First Window",0
ColorName      db   "New Color     ",0
ColorName0     db   "New is Blue   ",0
ColorName1     db   "New is Green  ",0
ColorName2     db   "New is Red    ",0
ColorName3     db   "New is White  ",0
MouseClick     db   0

char WPARAM 20h                         ; the character the program receives from keyboard
Count db 0

.DATA?              ;unitialized data
hInstance      HINSTANCE ?    ;instance handle of our program
CommandLine    LPSTR     ?
hWnd           HWND      ?    ;Handle to the edit control
maxX           DD        ?
maxY           DD        ?
ShapeNumber    dd        ?
startpoint     POINT     <>
endpoint       POINT     <>
hMemDC         HDC       ?
Bitmap         HBITMAP   ?
Brush          HBRUSH    ?
BrushColor     dd        ?

CharAsByte BYTE 1 Dup(?)        ; *
KeyboardString BYTE 128 Dup(?)      ; *

.CODE               ;here begins our code
start:
     invoke    GetModuleHandle, NULL        ;get the instance handle of our program
     mov       hInstance,eax
     invoke    GetCommandLine              ;get the command line

     mov       CommandLine,eax
     invoke    WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT  ;call the main function
     invoke    ExitProcess,eax             ;quit our program.  The exit code is returned in eax from WinMain.   

     WinMain   proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
          LOCAL wc:      WNDCLASSEX               ;create local variables on stack
          LOCAL msg:     MSG
          LOCAL hwnd:    HWND

          mov       wc.cbSize,SIZEOF WNDCLASSEX        ;create local variables on stack
          mov       wc.style,CS_HREDRAW or CS_VREDRAW
          mov       wc.lpfnWndProc, OFFSET WndProc
          mov       wc.cbClsExtra, 0
          mov       wc.cbWndExtra, 0
          push      hInstance
          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            ;register our window class
          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 LoadMenu,hInst,600                    ;load resource menu
          invoke SetMenu,hwnd,eax                      ;set it to main window

          invoke ShowWindow,hwnd,CmdShow               ;display our window on desktop
          invoke UpdateWindow,hwnd                     ;refresh the client area

          mov ShapeNumber, 1303                        ;text

          .WHILE TRUE                                  ;Enter message loop
               invoke GetMessage, ADDR msg, NULL, 0, 0
               .BREAK .IF (!eax)
               invoke TranslateMessage, ADDR msg
               invoke DispatchMessage, ADDR msg
          .ENDW
          mov       eax,msg.wParam                     ;return exit code in eax
          ret
     WinMain endp

     WndProc proc hwnd:HWND, uMsg:UINT, wParam:WPARAM, IParam:LPARAM
          LOCAL hdc:HDC
          LOCAL ps: PAINTSTRUCT
          .IF uMsg==WM_DESTROY                         ;if the user closes our  window
               invoke PostQuitMessage,NULL             ;quit our application
          .ELSEIF uMsg==WM_LBUTTONDOWN
               mov  eax, IParam
               and  eax, 0FFFFh
               mov  startpoint.x, eax
               mov  eax, IParam
               shr  eax,16
               mov  startpoint.y, eax
               ret
          .ELSEIF uMsg==WM_LBUTTONUP
               mov  eax, IParam
               and  eax, 0FFFFh
               mov  endpoint.x, eax
               mov  eax, IParam
               shr  eax, 16
               mov  endpoint.y, eax
               invoke    CreateSolidBrush, BrushColor
               mov  Brush, eax
               invoke SelectObject, hMemDC, Brush
                    .IF ShapeNumber==1302
                         invoke Rectangle, hMemDC, startpoint.x, startpoint.y, endpoint.x, endpoint.y
                         invoke InvalidateRect, hwnd, NULL, TRUE
                    .ELSEIF ShapeNumber==1301
                         invoke Ellipse, hMemDC, startpoint.x, startpoint.y, endpoint.x, endpoint.y
                         invoke InvalidateRect, hwnd, NULL, TRUE     
                    .ELSEIF ShapeNumber==1303
                         invoke lstrlen, ADDR ColorName
                         invoke TextOut, hMemDC, startpoint.x, startpoint.y, ADDR ColorName, eax
                         invoke InvalidateRect, hwnd, NULL, TRUE
                    .ENDIF

          .ELSEIF uMsg==WM_COMMAND
               .if wParam==1103
                    invoke SetTextColor,hMemDC,00ff0000h
                    mov    BrushColor, 0ff0000h
                    invoke lstrlen, ADDR ColorName0
                    invoke TextOut, hMemDC, 1, 1, ADDR ColorName0, eax
                    invoke InvalidateRect, hwnd, NULL, TRUE
                    ret
               .elseif wParam==1102
                    invoke SetTextColor,hMemDC, 0000ff00h
                    mov    BrushColor, 000ff00h
                    invoke lstrlen, ADDR ColorName1
                    invoke TextOut, hMemDC, 1, 1, ADDR ColorName1, eax
                    invoke InvalidateRect, hwnd, NULL, TRUE
                    ret
               .elseif wParam==1101
                    invoke SetTextColor, hMemDC, 000000ffh
                    mov    BrushColor, 00000ffh
                    invoke lstrlen, ADDR ColorName2
                    invoke TextOut, hMemDC, 1, 1, ADDR ColorName2, eax
                    invoke InvalidateRect, hwnd, NULL, TRUE
                    ret
               .elseif wParam==1301
                    mov    ShapeNumber, 1301
               .elseif wParam==1302
                    mov    ShapeNumber, 1302
               .elseif wParam==1303
                    mov    ShapeNumber, 1303
                    invoke DrawText, hdc, startpoint.x, startpoint.y, ADDR KeyboardString, eax
                    invoke InvalidateRect, hwnd, NULL, TRUE
                   

               .endif

          .ELSEIF uMsg==WM_CHAR
                 .IF wParam==01bh      ; * for esc
                     nop
                 .ELSEIF wParam==008h
                     mov eax, 00000000h
                     mov al, Count
                     mov esi, eax
                     mov bl, KeyboardString[esi]
                  .IF Count > 0                       
                              dec Count                     
                        mov eax, 00000000h           
                        mov al, Count                 
                        mov esi, eax                 
                        mov KeyboardString[esi], bl   
                  .ENDIF                             
       
                     invoke InvalidateRect, hWnd, NULL, TRUE
         
                 .ELSE
                      GET_BYTE:
                          push wParam
                          pop  char
                          mov eax, char
                          mov CharAsByte, al
                      ADD_TO_STRING:
                           mov eax, 00000000h
                           mov al, Count
                           mov esi, eax                       
                           mov bl, CharAsByte
                           mov KeyboardString[esi], bl
                           inc Count 
                           invoke InvalidateRect, hWnd,NULL,TRUE
         
                 .ENDIF


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

               invoke lstrlen, ADDR KeyboardString
               invoke TextOut, hdc, startpoint.x, startpoint.y, ADDR KeyboardString, eax

               ;invoke    BitBlt, hdc, 0, 0, maxX, maxY, hMemDC, 0, 0, SRCCOPY
               invoke    EndPaint, hwnd, ADDR ps

          .ELSEIF uMsg==WM_CREATE
               invoke    GetSystemMetrics, SM_CXSCREEN
               mov       maxX, eax
               invoke    GetSystemMetrics, SM_CYSCREEN
               mov       maxY, eax
               invoke    GetDC, hwnd
               mov       hdc, eax
               invoke    CreateCompatibleDC, hdc
               mov       hMemDC, eax
               invoke    CreateCompatibleBitmap, hdc, maxX, maxY
               mov       Bitmap, eax
               mov       hdc, eax
               invoke    SelectObject, hMemDC, Bitmap
               invoke    PatBlt, hMemDC, 0, 0, maxX, maxY, PATCOPY
               invoke    SetTextColor, hMemDC, 00ff0000h
               mov       BrushColor, 0ff0000h
               ;invoke    lstrlen, ADDR ColorName
               invoke    TextOut, hMemDC, 1, 1, ADDR ColorName, eax
               invoke    InvalidateRect, hwnd, NULL, TRUE
               ret
               
          .ELSE
               invoke DefWindowProc, hwnd, uMsg, wParam, IParam       ;default message processing
               ret
               
          .ENDIF

          xor eax, eax
          ret
          WndProc endp
end start






hutch--

The general drift is to create a compatible device context, draw what you want to it in the sequence you require THEN BitBlt it to the coordinates of the window's client area that you want.

dedndave

#2
the message box is easiest   :biggrin:
        INCLUDE \masm32\include\masm32rt.inc

        .DATA

szTitle db 'Title String',0
szMsg   db 'Message String',0

        .CODE

WinMain PROC

        INVOKE  MessageBox,0,offset szMsg,offset szTitle,MB_OK
        INVOKE  ExitProcess,eax

WinMain ENDP

        END     WinMain


the rest of it involves device contexts, as you say
there is a lot of material to read when it comes to painting and drawing
and, it isn't really easy to understand, either

it's late at night, here, and i am about to turn in
but, tomorrow, we can play a little more

i took a quick glance at your code, and it does appear to have a few basic problems
for one thing, whenever you create a DC or other type of GDI object, you should delete it when done
for brushes, pens, bitmaps, etc, we use DeleteObject
for DC's, we generally use DeleteDC, although DeleteObject is supposed to work
when you create a DC and select an object into it, SelectObject returns the handle of the original - you should save it for later
before you delete a DC, you should select the original objects back into it

Haleakala

Thank you both for the responses.  At least now I have a starting point to begin fixing up my code.   :greenclp:

Mikl__

; masm windows gui #
.586p
.model flat
include windows.inc
includelib kernel32.lib
includelib user32.lib
includelib gdi32.lib
extern _imp__LoadImageA@24:dword
extern _imp__ExitProcess@4:dword
extern _imp__CreatePatternBrush@4:dword
extern _imp__RegisterClassA@4:dword
extern _imp__CreateWindowExA@48:dword
extern _imp__GetMessageA@16:dword
extern _imp__DispatchMessageA@4:dword
extern _imp__DefWindowProcA@16:dword
extern _imp__BeginPaint@8:dword
extern _imp__EndPaint@8:dword
extern _imp__TextOutA@20:dword
extern _imp__SetBkMode@8:dword
.data
hDC dd ?
wTitle db "tweety78.bmp",0
Msg db "Hi, Haleakala!"
num = $ - Msg
.code
;---------------------------------------------------------
start: xor ebx,ebx
mov esi,400000h
mov edi,offset wTitle
;------------------------------
; registering the window class
;------------------------------
push edi
push ebx
push LR_LOADFROMFILE
push ebx
push ebx
push ebx
push edi
push esi
call _imp__LoadImageA@24
push eax
call _imp__CreatePatternBrush@4
push eax
push 10011h
push ebx
push esi
push ebx
push ebx
push offset window_procedure
push ebx
push esp
call _imp__RegisterClassA@4
;--------------------------+
; creating the main window |
;--------------------------+
push ebx
push esi
shl esi,9
push ebx
push ebx
push 305
push 286
push esi
push esi
push WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX or WS_VISIBLE
push edi
push edi
push ebx
call _imp__CreateWindowExA@48  
mov ebp,esp
;---------------------------+
; entering the message loop |
;---------------------------+
message_loop:push ebx
push ebx
push ebx
push ebp
call _imp__GetMessageA@16
push ebp
call _imp__DispatchMessageA@4
jmp message_loop
;----------------------+
; the window procedure |
;----------------------+
window_procedure:
hWnd equ [ebp+8]
uMsg equ [ebp+0Ch]
enter sizeof(PAINTSTRUCT),0
mov eax,uMsg
mov edi,hWnd
dec eax
dec eax
je short wmDESTROY
sub eax,WM_PAINT-WM_DESTROY
je wmPAINT
leave
jmp _imp__DefWindowProcA@16
wmDESTROY: push ebx
call _imp__ExitProcess@4
wmPAINT: push esp
push edi
call _imp__BeginPaint@8
push num
push offset Msg
push 100
push ebx
        push eax
push TRANSPARENT
push eax
call _imp__SetBkMode@8
call _imp__TextOutA@20
push esp
push edi
        call _imp__EndPaint@8
leave
retn 10h
end start

dedndave

ouch !
there is a little better way to terminate the program - i didn't look at the rest of the code
after the GetMessage call in the message loop, test for a 0 or -1 result in EAX, any other value, continue looping
the -1 value doesn't seem to be very likely - a lot of programmers just tests for 0
if it is 0 or -1, call ExitProcess with the exit code value from msg.wParam

to signal the loop to exit, use PostQuitMessage in WM_DESTROY

Mikl__

Quoteto signal the loop to exit, use PostQuitMessage in WM_DESTROY
I know it, but this method to complete the program I used many times in Windows XP and Seven, and everything works fine!
Let's look closely the entire program - there are still things to marvel :)

dedndave

ok, marveling.....
.....done